Open Excel and select Workbook and Worksheet below to start view changes to it's cells.
+
+ This example application listens for cell changes and when the value is TSLA, MSFT or AAPL it will
+ create an fdc3.instrument context object with the value as the ticker and broadcast it.
+
Use the channel API to send command to a platform.
+
+
+
+
+
+
+
+ This is a basic window app to represent an external app issuing commands to a platform to launch a
+ view. This app could be a java or a .net application as well as a web based application.
+
+
The buttons below let you:
+
+
Launch a platform app and connect to the command channel
+
Send a command to the platform to launch a view and pass some data
+
+ Send a command to the platform to launch a view, pass some data and tell it to place the view near a
+ specific window/view (in this case the last one launched)
+
+
+
+ When the platform is launched you will see the provider window show (it is generally hidden by
+ default). Once shown you can issue the createView commands from this application.
+
+
+
+
+
diff --git a/dev/john/update-window-options/use-logging-apis/js/app.bundle.js b/dev/john/update-window-options/use-logging-apis/js/app.bundle.js
new file mode 100644
index 00000000..9940a698
--- /dev/null
+++ b/dev/john/update-window-options/use-logging-apis/js/app.bundle.js
@@ -0,0 +1,35138 @@
+/******/ (() => { // webpackBootstrap
+/******/ var __webpack_modules__ = ({
+
+/***/ "../../node_modules/@openfin/core/out/mock.js":
+/*!****************************************************!*\
+ !*** ../../node_modules/@openfin/core/out/mock.js ***!
+ \****************************************************/
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+
+var require$$0 = __webpack_require__(/*! events */ "../../node_modules/events/events.js");
+var require$$3 = __webpack_require__(/*! lodash */ "../../node_modules/lodash/lodash.js");
+
+var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : typeof self !== 'undefined' ? self : {};
+
+var mock = {};
+
+var OpenFin$1 = {};
+
+var events = {};
+
+var application$1 = {};
+
+/**
+ * Namespace for events that can be emitted by an {@link OpenFin.Application}. Includes events
+ * re-propagated from the {@link OpenFin.Window} (and, transitively, {@link OpenFin.View}) level, prefixed with `window-` (and also, if applicable, `view-`).
+ * For example, a view's "attached" event will fire as 'window-view-attached' at the application level.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * This namespace contains only payload shapes for events that are unique to `Application`. Events that propagate to `Application` from
+ * child {@link OpenFin.Window windows} and {@link OpenFin.View views} are defined in the {@link OpenFin.WindowEvents} and
+ * {@link OpenFin.ViewEvents} namespaces. For a list of valid string keys for *all* application events, see {@link Application.on Application.on}.
+ *
+ * {@link ApplicationSourcedEvent Application-sourced events} (i.e. those that have not propagated from {@link OpenFin.ViewEvents Views}
+ * or {@link OpenFin.WindowEvents Windows} re-propagate to {@link OpenFin.SystemEvents System} with their type string prefixed with `application-`.
+ * {@link ApplicationWindowEvent Application events that are tied to Windows but do not propagate from them}
+ * are propagated to `System` without any type string prefixing.
+ *
+ * "Requested" events (e.g. {@link RunRequestedEvent}) do not propagate.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(application$1, "__esModule", { value: true });
+
+var base$1 = {};
+
+/**
+ * Namespace for shared event payloads and utility types common to all event emitters.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(base$1, "__esModule", { value: true });
+
+var externalApplication$1 = {};
+
+/**
+ * Namespace for events that can be transmitted by an {@link OpenFin.ExternalApplication}.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * For a list of valid string keys for external application events, see {@link ExternalApplication.on ExternalApplication.on}.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(externalApplication$1, "__esModule", { value: true });
+
+var frame$1 = {};
+
+Object.defineProperty(frame$1, "__esModule", { value: true });
+
+var globalHotkey$1 = {};
+
+/**
+ *
+ * Namespace for events that can be transmitted by {@link GlobalHotkey.GlobalHotkey}.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * For a list of valid string keys for global hotkey events, see {@link GlobalHotkey.GlobalHotkey.on GlobalHotkey.on}.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(globalHotkey$1, "__esModule", { value: true });
+
+var platform$1 = {};
+
+/**
+ *
+ * Namespace for events that can emitted by a {@link OpenFin.Platform}.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * The Platform `EventEmitter` is a superset of the {@link OpenFin.Application} `EventEmitter`,
+ * meaning it can listen to all {@link OpenFin.ApplicationEvents Application events} in addition to the
+ * Platform-specific events listed here. For a list of valid string keys for *all* platform events, see
+ * {@link Platform.on Platform.on}.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(platform$1, "__esModule", { value: true });
+
+var system$1 = {};
+
+/**
+ * Namespace for runtime-wide OpenFin events emitted by {@link System.System}. Includes events
+ * re-propagated from {@link OpenFin.Application}, {@link OpenFin.Window}, and {@link OpenFin.View} (prefixed with `application-`, `window-`, and `view-`). All
+ * event propagations are visible at the System level. Propagated events from WebContents (windows, views, frames) to the Application level will *not*
+ * transitively re-propagate to the System level, because they are already visible at the system level and contain the identity
+ * of the application. For example, an application's "closed" event will fire as 'application-closed' at the system level. A view's 'shown' event
+ * will be visible as 'view-shown' at the system level, but *not* as `application-window-view-shown`.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * This namespace contains only payload shapes for events that are unique to `System`. Events that propagate to `System` from
+ * child {@link OpenFin.Application applications}, {@link OpenFin.Window windows}, and {@link OpenFin.View views} are defined in the
+ * {@link OpenFin.ApplicationEvents}, {@link OpenFin.WindowEvents}, and {@link OpenFin.ViewEvents} namespaces. For a list of valid string keys for *all*
+ * system events, see {@link System.on System.on}.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(system$1, "__esModule", { value: true });
+
+var view$1 = {};
+
+/**
+ * Namespace for events that can be emitted by a {@link OpenFin.View}.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * This namespace contains only payload shapes for events that are unique to `View`. Events that are shared between all `WebContents`
+ * (i.e. {@link OpenFin.Window}, {@link OpenFin.View}) are defined in {@link OpenFin.WebContentsEvents}. For a list
+ * of valid string keys for *all* View events, see {@link View.on View.on}.
+ *
+ * View events propagate to their parent {@link OpenFin.WindowEvents Window}, {@link OpenFin.ApplicationEvents Application},
+ * and {@link OpenFin.SystemEvents System} with an added `viewIdentity` property and their event types prefixed with `'view-'`.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(view$1, "__esModule", { value: true });
+
+var webcontents = {};
+
+/**
+ * Namespace for events shared by all OpenFin WebContents elements (i.e. {@link OpenFin.Window},
+ * {@link OpenFin.View}).
+ *
+ * WebContents events will re-emit on parent entities - e.g., a propagating event in a view will also be emitted on the view's
+ * parent window, and propagating events in a window will also be emitted on the window's parent {@link OpenFin.Application}.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(webcontents, "__esModule", { value: true });
+
+var window$2 = {};
+
+/**
+ * Namespace for events that can be emitted by a {@link OpenFin.Window}.
+ *
+ * Event payloads are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * This namespace contains only payload shapes for events that are unique to `Window`. Events that are shared between all `WebContents`
+ * (i.e. {@link OpenFin.Window}, {@link OpenFin.View}) are defined in {@link OpenFin.WebContentsEvents}. Events that
+ * propagate from `View` are defined in {@link OpenFin.ViewEvents}. For a list of valid string keys for *all* Window events, see
+ * {@link Window.on Window.on}
+ *
+ * {@link OpenFin.WindowEvents.WindowSourcedEvent Window-sourced events} (i.e. those that are not propagated from a
+ * {@link OpenFin.ViewEvents View}) propagate to their parent {@link OpenFin.ApplicationEvents Application} and
+ * {@link OpenFin.SystemEvents System} with their event types prefixed with `'window-'`).
+ *
+ * "Requested" events (e.g. {@link AuthRequestedEvent}) do not propagate to `System. The {@link OpenFin.WindowEvents.WindowCloseRequestedEvent}
+ * does not propagate at all.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(window$2, "__esModule", { value: true });
+
+/**
+ * Namespace for OpenFin event types. Each entity that emits OpenFin events has its own sub-namespace. Event payloads
+ * themselves are documented as interfaces, while algebraic helper types and derived types are documented as type aliases.
+ *
+ * #### Event emitters
+ *
+ * The following entities emit OpenFin events, and have corresponding sub-namespaces:
+ *
+ * * {@link OpenFin.Application}: {@link OpenFin.ApplicationEvents}
+ * * {@link OpenFin.ExternalApplication}: {@link OpenFin.ExternalApplicationEvents}
+ * * {@link OpenFin.Frame}: {@link OpenFin.FrameEvents}
+ * * {@link OpenFin.GlobalHotkey}: {@link OpenFin.GlobalHotkeyEvents}
+ * * {@link OpenFin.Platform}: {@link OpenFin.PlatformEvents}
+ * * {@link OpenFin.System}: {@link OpenFin.SystemEvents}
+ * * {@link OpenFin.View}: {@link OpenFin.ViewEvents}
+ * * {@link OpenFin.Window}: {@link OpenFin.WindowEvents}
+ *
+ * These `EventEmitter` entities share a common set of methods for interacting with the OpenFin event bus, which can be
+ * seen on the individual documentation pages for each entity type.
+ *
+ * Registering event handlers is an asynchronous operation. It is important to ensure that the returned Promises are awaited to reduce the
+ * risk of race conditions.
+ *
+ * When the `EventEmitter` receives an event from the browser process and emits on the renderer, all of the functions attached to that
+ * specific event are called synchronously. Any values returned by the called listeners are ignored and will be discarded. If the window document
+ * is destroyed by page navigation or reload, its registered event listeners will be removed.
+ *
+ * We recommend using Arrow Functions for event listeners to ensure the this scope is consistent with the original function context.
+ *
+ * Events re-propagate from smaller/more-local scopes to larger/more-global scopes. For example, an event emitted on a specific
+ * view will propagate to the window in which the view is embedded, and then to the application in which the window is running, and
+ * finally to the OpenFin runtime itself at the "system" level. For details on propagation semantics, see the namespace for
+ * the propagating (or propagated-to) entity.
+ *
+ * If you need the payload type for a specific type of event (especially propagated events), use the emitting topic's `Payload` generic
+ * (e.g. {@link WindowEvents.Payload}) with the event's `type` string. For example, the payload of
+ * a {@link ViewEvents.CreatedEvent} after it has propagated to its parent {@link WindowEvents Window} can be found with
+ * `WindowEvents.Payload<'view-created'>`.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(events, "__esModule", { value: true });
+events.WindowEvents = events.WebContentsEvents = events.ViewEvents = events.SystemEvents = events.PlatformEvents = events.GlobalHotkeyEvents = events.FrameEvents = events.ExternalApplicationEvents = events.BaseEvents = events.ApplicationEvents = void 0;
+const ApplicationEvents = application$1;
+events.ApplicationEvents = ApplicationEvents;
+const BaseEvents = base$1;
+events.BaseEvents = BaseEvents;
+const ExternalApplicationEvents = externalApplication$1;
+events.ExternalApplicationEvents = ExternalApplicationEvents;
+const FrameEvents = frame$1;
+events.FrameEvents = FrameEvents;
+const GlobalHotkeyEvents = globalHotkey$1;
+events.GlobalHotkeyEvents = GlobalHotkeyEvents;
+const PlatformEvents = platform$1;
+events.PlatformEvents = PlatformEvents;
+const SystemEvents = system$1;
+events.SystemEvents = SystemEvents;
+const ViewEvents = view$1;
+events.ViewEvents = ViewEvents;
+const WebContentsEvents = webcontents;
+events.WebContentsEvents = WebContentsEvents;
+const WindowEvents = window$2;
+events.WindowEvents = WindowEvents;
+
+(function (exports) {
+ /**
+ * Top-level namespace for types referenced by the OpenFin API. Contains:
+ *
+ * * The type of the global `fin` entry point ({@link FinApi})
+ * * Classes that act as static namespaces returned from the `fin` global (e.g. {@link ApplicationModule}, accessible via `fin.Application`)
+ * * Instance classes that are returned from API calls (e.g. {@link Application}, accessible via `fin.Application.getCurrentSync()`)
+ * * Parameter shapes for API methods (e.g. {@link ApplicationOptions}, used in `fin.Application.start()`)
+ * * Event namespaces and payload union types (e.g. {@link ApplicationEvents} and {@link ApplicationEvent})
+ *
+ * @packageDocumentation
+ */
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ // Deprecated shim to preserve v30 namespace names
+ __exportStar(events, exports);
+} (OpenFin$1));
+
+var fin$1 = {};
+
+var system = {};
+
+var base = {};
+
+var promises = {};
+
+Object.defineProperty(promises, "__esModule", { value: true });
+promises.promiseMapSerial = promises.serial = promises.promiseMap = promises.promisify = void 0;
+function promisify(func) {
+ return (...args) => new Promise((resolve, reject) => {
+ func(...args, (err, val) => (err ? reject(err) : resolve(val)));
+ });
+}
+promises.promisify = promisify;
+async function promiseMap(arr, asyncF) {
+ return Promise.all(arr.map(asyncF));
+}
+promises.promiseMap = promiseMap;
+async function serial(arr) {
+ const ret = [];
+ for (const func of arr) {
+ // eslint-disable-next-line no-await-in-loop
+ const next = await func();
+ ret.push(next);
+ }
+ return ret;
+}
+promises.serial = serial;
+async function promiseMapSerial(arr, func) {
+ return serial(arr.map((value, index, array) => () => func(value, index, array)));
+}
+promises.promiseMapSerial = promiseMapSerial;
+
+var __classPrivateFieldSet$d = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$f = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _EmitterBase_emitterAccessor;
+Object.defineProperty(base, "__esModule", { value: true });
+base.Reply = base.EmitterBase = base.Base = void 0;
+const promises_1 = promises;
+class Base {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ this.isNodeEnvironment = () => {
+ return this.wire.environment.constructor.name === 'NodeEnvironment';
+ };
+ this.isOpenFinEnvironment = () => {
+ return this.wire.environment.constructor.name === 'OpenFinEnvironment';
+ };
+ this.isBrowserEnvironment = () => {
+ return this.wire.environment.constructor.name === 'BrowserEnvironment';
+ };
+ this.wire = wire;
+ }
+ get fin() {
+ return this.wire.getFin();
+ }
+ /**
+ * Provides access to the OpenFin representation of the current code context (usually a document
+ * such as a {@link OpenFin.View} or {@link OpenFin.Window}), as well as to the current `Interop` context.
+ *
+ * Useful for debugging in the devtools console, where this will intelligently type itself based
+ * on the context in which the devtools panel was opened.
+ */
+ get me() {
+ return this.wire.me;
+ }
+}
+base.Base = Base;
+/**
+ * An entity that emits OpenFin events.
+ *
+ * @remarks Event-binding methods are asynchronous as they must cross process boundaries
+ * and setup the listener in the browser process. When the `EventEmitter` receives an event from the browser process
+ * and emits on the renderer, all of the functions attached to that specific event are called synchronously. Any values
+ * returned by the called listeners are ignored and will be discarded. If the execution context of the window is destroyed
+ * by page navigation or reload, any events that have been setup in that context will be destroyed.
+ *
+ * It is important to keep in mind that when an ordinary listener function is called, the standard `this` keyword is intentionally
+ * set to reference the `EventEmitter` instance to which the listener is attached. It is possible to use ES6 Arrow Functions as
+ * listeners, however, when doing so, the `this` keyword will no longer reference the `EventEmitter` instance.
+ *
+ * Events re-propagate from smaller/more-local scopes to larger/more-global scopes. For example, an event emitted on a specific
+ * view will propagate to the window in which the view is embedded, and then to the application in which the window is running, and
+ * finally to the OpenFin runtime itself at the "system" level. Re-propagated events are prefixed with the name of the scope in which
+ * they originated - for example, a "shown" event emitted on a view will be re-propagated at the window level as "view-shown", and
+ * then to the application as "window-view-shown", and finally at the system level as "application-window-view-shown".
+ *
+ * All event propagations are visible at the System level, regardless of source, so transitive re-propagations (e.g. from view to window
+ * to application) are visible in their entirety at the system level. So, we can listen to the above event as "shown", "view-shown",
+ * "window-view-shown", or "application-window-view-shown."
+ */
+class EmitterBase extends Base {
+ constructor(wire, topic, ...additionalAccessors) {
+ super(wire);
+ this.topic = topic;
+ _EmitterBase_emitterAccessor.set(this, void 0);
+ this.eventNames = () => (this.hasEmitter() ? this.getOrCreateEmitter().eventNames() : []);
+ /**
+ * @internal
+ */
+ this.emit = (eventType, payload, ...args) => {
+ return this.hasEmitter() ? this.getOrCreateEmitter().emit(eventType, payload, ...args) : false;
+ };
+ this.hasEmitter = () => this.wire.eventAggregator.has(__classPrivateFieldGet$f(this, _EmitterBase_emitterAccessor, "f"));
+ this.getOrCreateEmitter = () => this.wire.eventAggregator.getOrCreate(__classPrivateFieldGet$f(this, _EmitterBase_emitterAccessor, "f"));
+ this.listeners = (type) => this.hasEmitter() ? this.getOrCreateEmitter().listeners(type) : [];
+ this.listenerCount = (type) => this.hasEmitter() ? this.getOrCreateEmitter().listenerCount(type) : 0;
+ this.registerEventListener = async (eventType, options = {}, applySubscription, undoSubscription) => {
+ const runtimeEvent = {
+ ...this.identity,
+ timestamp: options.timestamp || Date.now(),
+ topic: this.topic,
+ type: eventType
+ };
+ const emitter = this.getOrCreateEmitter();
+ // We apply the subscription and then undo if the async call fails to avoid
+ // indeterminacy in subscription application order, which can break things elsewhere
+ applySubscription(emitter);
+ try {
+ await this.wire.sendAction('subscribe-to-desktop-event', runtimeEvent);
+ }
+ catch (e) {
+ undoSubscription(emitter);
+ this.deleteEmitterIfNothingRegistered(emitter);
+ throw e;
+ }
+ };
+ this.deregisterEventListener = async (eventType, options = {}) => {
+ if (this.hasEmitter()) {
+ const runtimeEvent = {
+ ...this.identity,
+ timestamp: options.timestamp || Date.now(),
+ topic: this.topic,
+ type: eventType
+ };
+ await this.wire.sendAction('unsubscribe-to-desktop-event', runtimeEvent).catch(() => null);
+ const emitter = this.getOrCreateEmitter();
+ return emitter;
+ }
+ // This will only be reached if unsubscribe from event that does not exist but do not want to error here
+ return Promise.resolve();
+ };
+ __classPrivateFieldSet$d(this, _EmitterBase_emitterAccessor, [topic, ...additionalAccessors], "f");
+ this.listeners = (event) => this.hasEmitter() ? this.getOrCreateEmitter().listeners(event) : [];
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ *
+ * @remarks Event payloads are documented in the {@link OpenFin.Events} namespace.
+ */
+ async on(eventType, listener, options) {
+ await this.registerEventListener(eventType, options, (emitter) => {
+ emitter.on(eventType, listener);
+ }, (emitter) => {
+ emitter.removeListener(eventType, listener);
+ });
+ return this;
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ */
+ async addListener(eventType, listener, options) {
+ return this.on(eventType, listener, options);
+ }
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ *
+ * @remarks Event payloads are documented in the {@link OpenFin.Events} namespace.
+ */
+ async once(eventType, listener, options) {
+ const deregister = () => this.deregisterEventListener(eventType);
+ await this.registerEventListener(eventType, options, (emitter) => {
+ emitter.once(eventType, deregister);
+ emitter.once(eventType, listener);
+ }, (emitter) => {
+ emitter.removeListener(eventType, deregister);
+ emitter.removeListener(eventType, listener);
+ });
+ return this;
+ }
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ *
+ * @remarks Event payloads are documented in the {@link OpenFin.Events} namespace.
+ */
+ async prependListener(eventType, listener, options) {
+ await this.registerEventListener(eventType, options, (emitter) => {
+ emitter.prependListener(eventType, listener);
+ }, (emitter) => {
+ emitter.removeListener(eventType, listener);
+ });
+ return this;
+ }
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired,
+ * after which it is removed. The listener is added to the beginning of the listeners array.
+ *
+ * @remarks Event payloads are documented in the {@link OpenFin.Events} namespace.
+ */
+ async prependOnceListener(eventType, listener, options) {
+ const deregister = () => this.deregisterEventListener(eventType);
+ await this.registerEventListener(eventType, options, (emitter) => {
+ emitter.prependOnceListener(eventType, listener);
+ emitter.once(eventType, deregister);
+ }, (emitter) => {
+ emitter.removeListener(eventType, listener);
+ emitter.removeListener(eventType, deregister);
+ });
+ return this;
+ }
+ /**
+ * Remove a listener from the listener array for the specified event.
+ *
+ * @remarks Caution: Calling this method changes the array indices in the listener array behind the listener.
+ */
+ async removeListener(eventType, listener, options) {
+ const emitter = await this.deregisterEventListener(eventType, options);
+ if (emitter) {
+ emitter.removeListener(eventType, listener);
+ this.deleteEmitterIfNothingRegistered(emitter);
+ }
+ return this;
+ }
+ async deregisterAllListeners(eventType) {
+ const runtimeEvent = { ...this.identity, type: eventType, topic: this.topic };
+ if (this.hasEmitter()) {
+ const emitter = this.getOrCreateEmitter();
+ const refCount = emitter.listenerCount(runtimeEvent.type);
+ const unsubscribePromises = [];
+ for (let i = 0; i < refCount; i++) {
+ unsubscribePromises.push(this.wire.sendAction('unsubscribe-to-desktop-event', runtimeEvent).catch(() => null));
+ }
+ await Promise.all(unsubscribePromises);
+ return emitter;
+ }
+ return undefined;
+ }
+ /**
+ * Removes all listeners, or those of the specified event.
+ *
+ */
+ async removeAllListeners(eventType) {
+ const removeByEvent = async (event) => {
+ const emitter = await this.deregisterAllListeners(event);
+ if (emitter) {
+ emitter.removeAllListeners(event);
+ this.deleteEmitterIfNothingRegistered(emitter);
+ }
+ };
+ if (eventType) {
+ await removeByEvent(eventType);
+ }
+ else if (this.hasEmitter()) {
+ const events = this.getOrCreateEmitter().eventNames();
+ await (0, promises_1.promiseMap)(events, removeByEvent);
+ }
+ return this;
+ }
+ deleteEmitterIfNothingRegistered(emitter) {
+ if (emitter.eventNames().length === 0) {
+ this.wire.eventAggregator.delete(__classPrivateFieldGet$f(this, _EmitterBase_emitterAccessor, "f"));
+ }
+ }
+}
+base.EmitterBase = EmitterBase;
+_EmitterBase_emitterAccessor = new WeakMap();
+class Reply {
+}
+base.Reply = Reply;
+
+var transportErrors = {};
+
+Object.defineProperty(transportErrors, "__esModule", { value: true });
+transportErrors.RuntimeError = transportErrors.NotSupportedError = transportErrors.NotImplementedError = transportErrors.NoAckError = transportErrors.DuplicateCorrelationError = transportErrors.UnexpectedActionError = transportErrors.DisconnectedError = void 0;
+class DisconnectedError extends Error {
+ constructor(readyState) {
+ super(`Expected websocket state OPEN but found ${readyState}`);
+ this.readyState = readyState;
+ }
+}
+transportErrors.DisconnectedError = DisconnectedError;
+class UnexpectedActionError extends Error {
+}
+transportErrors.UnexpectedActionError = UnexpectedActionError;
+class DuplicateCorrelationError extends Error {
+}
+transportErrors.DuplicateCorrelationError = DuplicateCorrelationError;
+class NoAckError extends Error {
+}
+transportErrors.NoAckError = NoAckError;
+class NotImplementedError extends Error {
+}
+transportErrors.NotImplementedError = NotImplementedError;
+class NotSupportedError extends Error {
+}
+transportErrors.NotSupportedError = NotSupportedError;
+class InternalError extends Error {
+ constructor(err) {
+ const { message, name, stack, ...rest } = err;
+ super(message);
+ this.name = name || 'Error';
+ this.stack = stack ?? this.toString();
+ Object.keys(rest).forEach(key => {
+ this[key] = rest[key];
+ });
+ }
+}
+// For documentation of the error methods being used see here: https://v8.dev/docs/stack-trace-api
+class RuntimeError extends Error {
+ static getCallSite(callsToRemove = 0) {
+ const length = Error.stackTraceLimit;
+ const realCallsToRemove = callsToRemove + 1; // remove this call;
+ Error.stackTraceLimit = length + realCallsToRemove;
+ // eslint-disable-next-line no-underscore-dangle
+ const _prepareStackTrace = Error.prepareStackTrace;
+ // This will be called when we access the `stack` property
+ Error.prepareStackTrace = (_, stack) => stack;
+ // stack is optional in non chromium contexts
+ const stack = new Error().stack?.slice(realCallsToRemove) ?? [];
+ Error.prepareStackTrace = _prepareStackTrace;
+ Error.stackTraceLimit = length;
+ return stack;
+ }
+ static prepareStackTrace(err, callSites) {
+ if (typeof Error.prepareStackTrace === 'function') {
+ return Error.prepareStackTrace(err, callSites);
+ }
+ let string = "";
+ string += err.name || "Error";
+ string += `: ${err.message || ""}`;
+ for (const callSite of callSites) {
+ string += `\n at ${callSite.toString()}`;
+ }
+ return string;
+ }
+ ;
+ constructor(payload, callSites) {
+ const { reason, error } = payload;
+ super(reason);
+ this.name = 'RuntimeError';
+ if (error?.stack) {
+ this.cause = new InternalError(error);
+ }
+ if (callSites) {
+ this.stack = RuntimeError.prepareStackTrace(this, callSites);
+ }
+ }
+}
+transportErrors.RuntimeError = RuntimeError;
+
+var window$1 = {};
+
+var Factory$8 = {};
+
+var validate = {};
+
+Object.defineProperty(validate, "__esModule", { value: true });
+validate.validateIdentity = void 0;
+function validateIdentity(identity) {
+ let errorMsg;
+ if (typeof identity !== 'object' || typeof identity.uuid !== 'string') {
+ errorMsg = 'Not a valid identity object';
+ }
+ return errorMsg;
+}
+validate.validateIdentity = validateIdentity;
+
+var Instance$7 = {};
+
+var application = {};
+
+var Factory$7 = {};
+
+var Instance$6 = {};
+
+var view = {};
+
+var Factory$6 = {};
+
+var warnings = {};
+
+Object.defineProperty(warnings, "__esModule", { value: true });
+warnings.handleDeprecatedWarnings = void 0;
+const handleDeprecatedWarnings = (options) => {
+ if (options.contentNavigation?.whitelist ||
+ options.contentNavigation?.blacklist ||
+ options.contentRedirect?.whitelist ||
+ options.contentRedirect?.blacklist) {
+ console.warn(`The properties 'whitelist' and 'blacklist' have been marked as deprecated and will be removed in a future version. Please use 'allowlist' and 'denylist'.`);
+ }
+};
+warnings.handleDeprecatedWarnings = handleDeprecatedWarnings;
+
+var hasRequiredFactory$3;
+
+function requireFactory$3 () {
+ if (hasRequiredFactory$3) return Factory$6;
+ hasRequiredFactory$3 = 1;
+ Object.defineProperty(Factory$6, "__esModule", { value: true });
+ Factory$6.ViewModule = void 0;
+ const base_1 = base;
+ const validate_1 = validate;
+ const index_1 = requireView();
+ const warnings_1 = warnings;
+ /**
+ * Static namespace for OpenFin API methods that interact with the {@link View} class, available under `fin.View`.
+ */
+ class ViewModule extends base_1.Base {
+ /**
+ * Creates a new View.
+ * @param options - View creation options
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameCreate',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * createView()
+ * .then((createdView) => {
+ * view = createdView;
+ * console.log('View created.', view);
+ * view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ * })
+ * .catch(err => console.log(err));
+ * ```
+ * Note that created views needs to navigate somewhere for them to actually render a website.
+ * @experimental
+ */
+ async create(options) {
+ const { uuid } = this.wire.me;
+ if (!options.name || typeof options.name !== 'string') {
+ throw new Error('Please provide a name property as a string in order to create a View.');
+ }
+ (0, warnings_1.handleDeprecatedWarnings)(options);
+ if (this.wire.environment.childViews) {
+ await this.wire.environment.createChildContent({
+ entityType: 'view',
+ options: { ...options, uuid }
+ });
+ }
+ else {
+ await this.wire.sendAction('create-view', { ...options, uuid });
+ }
+ return this.wrapSync({ uuid, name: options.name });
+ }
+ /**
+ * Asynchronously returns a View object that represents an existing view.
+ *
+ * @example
+ * ```js
+ * fin.View.wrap({ uuid: 'testViewUuid', name: 'testViewName' }))
+ * .then(view => console.log('wrapped view', view))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ async wrap(identity) {
+ this.wire.sendAction('view-wrap');
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new index_1.View(this.wire, identity);
+ }
+ /**
+ * Synchronously returns a View object that represents an existing view.
+ *
+ * @example
+ * ```js
+ * const view = fin.View.wrapSync({ uuid: 'testView', name: 'testViewName' });
+ * await view.hide();
+ * ```
+ * @experimental
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('view-wrap-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new index_1.View(this.wire, identity);
+ }
+ /**
+ * Asynchronously returns a View object that represents the current view
+ *
+ * @example
+ * ```js
+ * fin.View.getCurrent()
+ * .then(view => console.log('current view', view))
+ * .catch(err => console.log(err));
+ *
+ * ```
+ * @experimental
+ */
+ getCurrent() {
+ this.wire.sendAction('view-get-current').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ if (!this.wire.me.isView) {
+ throw new Error('You are not in a View context');
+ }
+ const { uuid, name } = this.wire.me;
+ return this.wrap({ uuid, name });
+ }
+ /**
+ * Synchronously returns a View object that represents the current view
+ *
+ * @example
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ * console.log(view);
+ *
+ * ```
+ * @experimental
+ */
+ getCurrentSync() {
+ this.wire.sendAction('view-get-current-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ if (!this.wire.me.isView) {
+ throw new Error('You are not in a View context');
+ }
+ const { uuid, name } = this.wire.me;
+ return this.wrapSync({ uuid, name });
+ }
+ }
+ Factory$6.ViewModule = ViewModule;
+ return Factory$6;
+}
+
+var Instance$5 = {};
+
+var lazy = {};
+
+Object.defineProperty(lazy, "__esModule", { value: true });
+lazy.AsyncRetryableLazy = lazy.Lazy = void 0;
+/**
+ * Handy class for managing asynchronous dependencies of classes.
+ *
+ * Will call the producer function once and only once when getValue is called,
+ * returning the resultant value for every subsequent call.
+ */
+class Lazy {
+ // eslint-disable-next-line
+ constructor(producerFn) {
+ this.producerFn = producerFn;
+ }
+ /**
+ * Lazily get the value returned by the producer.
+ * @returns The value returned from the producer function
+ */
+ getValue() {
+ if (!this.value) {
+ this.value = this.producerFn();
+ }
+ return this.value;
+ }
+}
+lazy.Lazy = Lazy;
+/**
+ * Handy class for managing asynchronous dependencies of classes.
+ *
+ * Will call asynchronous producer only after `getValue` is called. If the
+ * deferred code errors, we can try it again by re-calling `getValue` after
+ * the promise rejects.
+ */
+class AsyncRetryableLazy {
+ // eslint-disable-next-line
+ constructor(producerFn) {
+ this.producerFn = producerFn;
+ }
+ /**
+ * Lazily get the value returned by the async producer.
+ *
+ * @returns The value returned from the producer function
+ */
+ async getValue() {
+ if (!this.promise) {
+ this.promise = this.producerFn().catch((e) => {
+ delete this.promise;
+ throw e;
+ });
+ }
+ return this.promise;
+ }
+}
+lazy.AsyncRetryableLazy = AsyncRetryableLazy;
+
+var layoutEntities = {};
+
+var apiExposer$1 = {};
+
+var apiConsumer = {};
+
+Object.defineProperty(apiConsumer, "__esModule", { value: true });
+apiConsumer.ApiConsumer = void 0;
+/**
+ * Consumer for apis exposed with {@see ApiExposer}.
+ *
+ * A strategy that matches the strategy used to expose a target API must be provided.
+ */
+class ApiConsumer {
+ // eslint-disable-next-line
+ constructor(strategy) {
+ this.strategy = strategy;
+ /**
+ * Consumes an api exposed using a given transport strategy, and generates a client
+ * for easy, type safe consumption of that client.
+ * @param options Strategy specific consumption options.
+ * @returns An api client matching the given type.
+ */
+ this.consume = async (options) => {
+ const exposedProperties = await this.strategy.getExposedFunctions(options);
+ return exposedProperties.reduce((client, prop) => ({
+ ...client,
+ [prop.key]: this.strategy.createFunction(prop, options)
+ }), {});
+ };
+ }
+}
+apiConsumer.ApiConsumer = ApiConsumer;
+
+var apiExposer = {};
+
+var decorators = {};
+
+Object.defineProperty(decorators, "__esModule", { value: true });
+decorators.expose = decorators.getExposedProperties = void 0;
+const exposedProperties = Symbol('exposedProperties');
+const getExposedProperties = (target) => {
+ return target[exposedProperties] || target.prototype[exposedProperties] || [];
+};
+decorators.getExposedProperties = getExposedProperties;
+/**
+ * Indicates that a class member function can be exposed using {@link ApiExposer}.
+ * @param options Options specific to the strategy used in {@link ApiExposer}
+ */
+// Returns any as decorator typing is weird.
+const expose = (options) => (target, key, descriptor) => {
+ target[exposedProperties] = target[exposedProperties] || [];
+ target[exposedProperties].push({ key, descriptor, options });
+};
+decorators.expose = expose;
+
+Object.defineProperty(apiExposer, "__esModule", { value: true });
+apiExposer.ApiExposer = void 0;
+const decorators_1 = decorators;
+/**
+ * Exposes api services on the transport of choice.
+ */
+class ApiExposer {
+ /**
+ * @param strategy The expose strategy to use to expose instances.
+ */
+ // eslint-disable-next-line
+ constructor(strategy) {
+ this.strategy = strategy;
+ /**
+ * Exposes an instance of a given api on
+ * @param instance Instance of a class which has been decorated to indicate which functions can be exposed.
+ * @param instanceOptions Transport strategy specific options to use when exposing.
+ */
+ this.exposeInstance = async (instance, instanceOptions) => {
+ const exposableProps = (0, decorators_1.getExposedProperties)(instance);
+ const exposedProps = await Promise.all(exposableProps.map(async ({ key, options }) => {
+ const customConsumptionOptions = await this.strategy.exposeFunction(instance[key].bind(instance), {
+ key,
+ options,
+ meta: instanceOptions
+ });
+ return {
+ key,
+ options: customConsumptionOptions
+ };
+ }));
+ await this.strategy.exposeMeta(instanceOptions, exposedProps);
+ };
+ }
+ ;
+}
+apiExposer.ApiExposer = ApiExposer;
+
+var strategies = {};
+
+var openfinChannels = {};
+
+var channelsConsumer = {};
+
+Object.defineProperty(channelsConsumer, "__esModule", { value: true });
+channelsConsumer.ChannelsConsumer = void 0;
+class ChannelsConsumer {
+ // eslint-disable-next-line
+ constructor(channel) {
+ this.channel = channel;
+ this.getExposedFunctions = async (options) => {
+ const { id } = options;
+ const { props } = await this.channel.dispatch(`api-meta:${id}`);
+ return props;
+ };
+ this.createFunction = (prop) => (...args) => {
+ const { action } = prop.options;
+ return this.channel.dispatch(action, { args });
+ };
+ }
+ ;
+}
+channelsConsumer.ChannelsConsumer = ChannelsConsumer;
+
+var channelsExposer = {};
+
+Object.defineProperty(channelsExposer, "__esModule", { value: true });
+channelsExposer.ChannelsExposer = void 0;
+class ChannelsExposer {
+ // eslint-disable-next-line
+ constructor(channelProviderOrClient) {
+ this.channelProviderOrClient = channelProviderOrClient;
+ this.exposeFunction = async (target, config) => {
+ const { key, options, meta } = config;
+ const { id } = meta;
+ const action = `${id}.${options?.action || key}`;
+ await this.channelProviderOrClient.register(action, async ({ args }) => {
+ return target(...args);
+ });
+ return { action };
+ };
+ this.exposeMeta = async ({ id }, props) => {
+ const action = `api-meta:${id}`;
+ await this.channelProviderOrClient.register(action, () => ({ props }));
+ };
+ }
+}
+channelsExposer.ChannelsExposer = ChannelsExposer;
+
+(function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(channelsConsumer, exports);
+ __exportStar(channelsExposer, exports);
+} (openfinChannels));
+
+(function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(openfinChannels, exports);
+} (strategies));
+
+(function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(apiConsumer, exports);
+ __exportStar(apiExposer, exports);
+ __exportStar(strategies, exports);
+ __exportStar(decorators, exports);
+} (apiExposer$1));
+
+var channelApiRelay = {};
+
+Object.defineProperty(channelApiRelay, "__esModule", { value: true });
+channelApiRelay.createRelayedDispatch = channelApiRelay.relayChannelClientApi = void 0;
+const EXPECTED_ERRORS = [
+ 'no longer connected',
+ 'RTCDataChannel closed unexpectedly',
+ 'The client you are trying to dispatch from is disconnected from the target provider',
+];
+// Checks possible error messages that we want to trap, client error message can originate
+// from ChannelProvider::dispatch OR ClassicStrategy::closeEndpoint OR RTCEndPoint::dataChannel::onclose
+const isDisconnectedError = (errorMsg) => {
+ return EXPECTED_ERRORS.some(e => errorMsg.includes(e));
+};
+/**
+ * @internal
+ * Create a channel relay for a given channel exposition, allowing a single provider to route
+ * actions to the designated clients.
+ *
+ * Designed to be used in conjunction with @expose
+ *
+ * @param channelProvider The channel provider to relay the actions on.
+ * @param config Determines which actions to relay. Please ensure action prefix matches the exposed api.
+ */
+const relayChannelClientApi = async (channelProvider, relayId) => {
+ channelProvider.register(`relay:${relayId}`, ({ action, target, payload }) => {
+ return channelProvider.dispatch(target, action, payload);
+ });
+ await Promise.resolve();
+};
+channelApiRelay.relayChannelClientApi = relayChannelClientApi;
+const createRelayedDispatch = (client, target, relayId, relayErrorMsg) => async (action, payload) => {
+ try {
+ return await client.dispatch(`relay:${relayId}`, {
+ action,
+ payload,
+ target
+ });
+ }
+ catch (e) {
+ if (isDisconnectedError(e.message) && relayErrorMsg) {
+ throw new Error(relayErrorMsg);
+ }
+ throw e;
+ }
+};
+channelApiRelay.createRelayedDispatch = createRelayedDispatch;
+
+var __classPrivateFieldSet$c = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$e = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _LayoutNode_client, _TabStack_client, _ColumnOrRow_client;
+Object.defineProperty(layoutEntities, "__esModule", { value: true });
+layoutEntities.ColumnOrRow = layoutEntities.TabStack = layoutEntities.LayoutNode = void 0;
+const api_exposer_1 = apiExposer$1;
+const channel_api_relay_1 = channelApiRelay;
+/*
+ This file includes LayoutNode, ColumnOrRow and TabStack classes, which are all closely
+ intertwined, and share members via parent abstract class LayoutNode. To prevent circular
+ refs, we define and export all the classes here.
+*/
+/**
+ * @ignore
+ * @internal
+ * Supplies an ApiClient for {@link LayoutEntitiesController} and helper methods
+ * for the entities {@link TabStack} AND {@link ColumnOrRow} to use.
+ */
+class LayoutNode {
+ /**
+ * @internal
+ * @ignore
+ */
+ constructor(client, entityId) {
+ /**
+ * @ignore
+ * @internal
+ * ApiClient for {@link LayoutEntitiesController}
+ */
+ _LayoutNode_client.set(this, void 0);
+ /**
+ * Checks if the TabStack or ColumnOrRow is the root content item
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * const isRoot = await stack.isRoot();
+ * // The TabStack is root: false
+ * console.log(`The TabStack is root: ${isRoot}`);
+ *
+ * // Retrieves the parent ColumnOrRow
+ * const parent = await stack.getParent();
+ * const parentIsRoot = await parent.isRoot();
+ * // The parent ColumnOrRow is root: true
+ * console.log(`The parent ColumnOrRow is root: ${parentIsRoot}`);
+ * ```
+ */
+ this.isRoot = () => __classPrivateFieldGet$e(this, _LayoutNode_client, "f").isRoot(this.entityId);
+ /**
+ * Checks if the TabStack or ColumnOrRow exists
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Retrieves the parent ColumnOrRow
+ * const columnOrRow = await stack.getParent();
+ * let exists = await stack.exists();
+ * // or
+ * let exists = await columnOrRow.exists();
+ * // The entity exists: true
+ * console.log(`The entity exists: ${exists}`);
+ * ```
+ */
+ this.exists = () => __classPrivateFieldGet$e(this, _LayoutNode_client, "f").exists(this.entityId);
+ /**
+ * Retrieves the parent of the TabStack or ColumnOrRow
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Retrieves the parent ColumnOrRow
+ * const columnOrRow = await stack.getParent();
+ *
+ * // undefined if entity is the root item
+ * let parent = await columnOrRow.getParent();
+ * // or
+ * let parent = await stack.getParent();
+ * ```
+ */
+ this.getParent = async () => {
+ const parent = await __classPrivateFieldGet$e(this, _LayoutNode_client, "f").getParent(this.entityId);
+ if (!parent) {
+ return undefined;
+ }
+ return LayoutNode.getEntity(parent, __classPrivateFieldGet$e(this, _LayoutNode_client, "f"));
+ };
+ /**
+ * Creates a new TabStack adjacent to the given TabStack or ColumnOrRow. Inputs can be new views to create, or existing views.
+ *
+ * Known Issue: If the number of views to add overflows the tab-container, the added views will be set as active
+ * during each render, and then placed at the front of the tab-stack, while the underlying order of tabs will remain unchanged.
+ * This means the views you pass to createAdjacentStack() may not render in the order given by the array.
+ * Until fixed, this problem can be avoided only if your window is wide enough to fit creating all the views in the tabstack.
+ *
+ * @param views The views that will populate the new TabStack.
+ * @param options Additional options that control new TabStack creation.
+ * @returns The newly-created TabStack.
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * const columnOrRow = await stack.getParent();
+ *
+ * // Create view references by supplying a 'name' and 'url'
+ * const views = [
+ * // if 'name' is undefined, one will be generated
+ * // if 'url' is undefined, it will default the view URL to 'about:blank'
+ * { name: 'google-view', url: 'http://google.com/'},
+ * { name: 'of-developers-view', url: 'http://developers.openfin.co/'},
+ * ];
+ *
+ * // Create a view beforehand to be included in the new tab stack
+ * const outsideView = await fin.View.create({
+ * name: 'outside-bloomberg-view',
+ * url: 'https://bloomberg.com/',
+ * target: fin.me.identity,
+ * });
+ *
+ * // Views to add can be identities, or the reference views mentioned above
+ * const viewsToAdd = [outsideView.identity, ...views];
+ *
+ * // Possible position inputs: 'right' | 'left' | 'top' | 'bottom'
+ * let stackFrom = await columnOrRow.createAdjacentStack(viewsToAdd, { position: 'right' });
+ * // Or
+ * let newStack = await stack.createAdjacentStack(viewsToAdd, { position: 'right' });
+ * console.log(`A new TabStack created to the right has ${newStack.length} views in it`);
+ *
+ * ```
+ * @experimental
+ */
+ this.createAdjacentStack = async (views, options) => {
+ const entityId = await __classPrivateFieldGet$e(this, _LayoutNode_client, "f").createAdjacentStack(this.entityId, views, options);
+ return LayoutNode.getEntity({ entityId, type: 'stack' }, __classPrivateFieldGet$e(this, _LayoutNode_client, "f"));
+ };
+ /**
+ * Retrieves the adjacent TabStacks of the given TabStack or ColumnOrRow.
+ *
+ * @param edge Edge whose adjacent TabStacks will be returned.
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * const columnOrRow = await stack.getParent();
+ * // Possible position inputs: 'right' | 'left' | 'top' | 'bottom'
+ * let rightStacks = await columnOrRow.getAdjacentStacks('right');
+ * let leftStacks = await columnOrRow.getAdjacentStacks('left');
+ * // or
+ * let rightStacks = await stack.getAdjacentStacks('right');
+ * let leftStacks = await stack.getAdjacentStacks('left');
+ *
+ * console.log(`The entity has ${rightStacks.length} stacks to the right, and ${leftStacks.length} stacks to the left`);
+ *
+ * ```
+ * @experimental
+ */
+ this.getAdjacentStacks = async (edge) => {
+ const adjacentStacks = await __classPrivateFieldGet$e(this, _LayoutNode_client, "f").getAdjacentStacks({
+ targetId: this.entityId,
+ edge
+ });
+ return adjacentStacks.map((stack) => LayoutNode.getEntity({
+ type: 'stack',
+ entityId: stack.entityId
+ }, __classPrivateFieldGet$e(this, _LayoutNode_client, "f")));
+ };
+ __classPrivateFieldSet$c(this, _LayoutNode_client, client, "f");
+ this.entityId = entityId;
+ }
+}
+layoutEntities.LayoutNode = LayoutNode;
+_LayoutNode_client = new WeakMap();
+/**
+ * @ignore
+ * @internal
+ * Encapsulates Api consumption of {@link LayoutEntitiesClient} with a relayed dispatch
+ * @param client
+ * @param controllerId
+ * @param identity
+ * @returns a new instance of {@link LayoutEntitiesClient} with bound to the controllerId
+ */
+LayoutNode.newLayoutEntitiesClient = async (client, controllerId, identity) => {
+ const dispatch = (0, channel_api_relay_1.createRelayedDispatch)(client, identity, 'layout-relay', 'You are trying to interact with a layout component on a window that does not exist or has been destroyed.');
+ const consumer = new api_exposer_1.ApiConsumer(new api_exposer_1.ChannelsConsumer({ dispatch }));
+ return consumer.consume({ id: controllerId });
+};
+LayoutNode.getEntity = (definition, client) => {
+ const { entityId, type } = definition;
+ switch (type) {
+ case 'column':
+ case 'row':
+ return new ColumnOrRow(client, entityId, type);
+ case 'stack':
+ return new TabStack(client, entityId);
+ default:
+ throw new Error(`Unrecognised Layout Entity encountered ('${JSON.stringify(definition)})`);
+ }
+};
+/**
+ * A TabStack is used to manage the state of a stack of tabs within an OpenFin Layout.
+ */
+class TabStack extends LayoutNode {
+ /** @internal */
+ constructor(client, entityId) {
+ super(client, entityId);
+ /**
+ * @internal
+ * ApiClient for {@link LayoutEntitiesController}
+ */
+ _TabStack_client.set(this, void 0);
+ /**
+ * Type of the content item. Always stack, but useful for distinguishing between a {@link TabStack} and {@link ColumnOrRow}.
+ */
+ this.type = 'stack';
+ /**
+ * Retrieves a list of all views belonging to this {@link TabStack}.
+ *
+ * Known Issue: If adding a view overflows the tab-container width, the added view will be set as active
+ * and rendered at the front of the tab-stack, while the underlying order of tabs will remain unchanged.
+ * If that happens and then getViews() is called, it will return the identities in a different order than
+ * than the currently rendered tab order.
+ *
+ *
+ * @throws If the {@link TabStack} has been destroyed.
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Alternatively, you can wrap any view and get the stack from there
+ * // const viewFromSomewhere = fin.View.wrapSync(someView.identity);
+ * // const stack = await viewFromSomewhere.getCurrentStack();
+ * const views = await stack.getViews();
+ * console.log(`Stack contains ${views.length} view(s)`);
+ * ```
+ * @experimental
+ */
+ this.getViews = () => __classPrivateFieldGet$e(this, _TabStack_client, "f").getStackViews(this.entityId);
+ /**
+ * Adds or creates a view in this {@link TabStack}.
+ *
+ * @remarks Known Issue: If adding a view overflows the tab-container, the added view will be set as active
+ * and rendered at the front of the tab-stack, while the underlying order of tabs will remain unchanged.
+ *
+ * @param view The identity of an existing view to add, or options to create a view.
+ * @param options Optional view options: index number used to insert the view into the stack at that index. Defaults to 0 (front of the stack)
+ * @returns Resolves with the {@link OpenFin.Identity identity} of the added view.
+ * @throws If the view does not exist or fails to create.
+ * @throws If the {@link TabStack} has been destroyed.
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Alternatively, you can wrap any view and get the stack from there
+ * // const viewFromSomewhere = fin.View.wrapSync(someView.identity);
+ * // const stack = await viewFromSomewhere.getCurrentStack();
+ * const googleViewIdentity = await stack.addView({ name: 'google-view', url: 'http://google.com/' });
+ * console.log('Identity of the google view just added', { googleViewIdentity });
+ * // pass in { index: number } to set the index in the stack. Here 1 means, end of the stack (defaults to 0)
+ * const appleViewIdentity = await stack.addView({ name: 'apple-view', url: 'http://apple.com/' }, { index: 1 });
+ * console.log('Identity of the apple view just added', { appleViewIdentity });
+ * ```
+ * @experimental
+ */
+ this.addView = async (view, options = { index: 0 }) => __classPrivateFieldGet$e(this, _TabStack_client, "f").addViewToStack(this.entityId, view, options);
+ /**
+ * Removes a view from this {@link TabStack}.
+ *
+ * @remarks Throws an exception if the view identity does not exist or was already destroyed.
+ *
+ * @param view - Identity of the view to remove.
+ * @throws If the view does not exist or does not belong to the stack.
+ * @throws If the {@link TabStack} has been destroyed.
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * const googleViewIdentity = await stack.addView({ name: 'google-view', url: 'http://google.com/' });
+ *
+ * await stack.removeView(googleViewIdentity);
+ *
+ * try {
+ * await stack.removeView(googleViewIdentity);
+ * } catch (error) {
+ * // Tried to remove a view ('google-view') which does not belong to the stack.
+ * console.log(error);
+ * }
+ * ```
+ */
+ this.removeView = async (view) => {
+ await __classPrivateFieldGet$e(this, _TabStack_client, "f").removeViewFromStack(this.entityId, view);
+ };
+ /**
+ * Sets the active view of the {@link TabStack} without focusing it.
+ * @param view - Identity of the view to activate.
+ * @returns Promise which resolves with void once the view has been activated.
+ * @throws If the {@link TabStack} has been destroyed.
+ * @throws If the view does not exist.
+ * @example
+ * Change the active tab of a known View's TabStack:
+ * ```js
+ * const targetView = fin.View.wrapSync({ uuid: 'uuid', name: 'view-name' });
+ * const stack = await targetView.getCurrentStack();
+ * await stack.setActiveView(targetView.identity);
+ * ```
+ *
+ * Set the current View as active within its TabStack:
+ * ```js
+ * const stack = await fin.me.getCurrentStack();
+ * await stack.setActiveView(fin.me.identity);
+ * ```
+ * @experimental
+ */
+ this.setActiveView = async (view) => {
+ await __classPrivateFieldGet$e(this, _TabStack_client, "f").setStackActiveView(this.entityId, view);
+ };
+ __classPrivateFieldSet$c(this, _TabStack_client, client, "f");
+ }
+}
+layoutEntities.TabStack = TabStack;
+_TabStack_client = new WeakMap();
+/**
+ * A ColumnOrRow is used to manage the state of Column and Rows within an OpenFin Layout.
+ */
+class ColumnOrRow extends LayoutNode {
+ /**
+ * @internal
+ */
+ constructor(client, entityId, type) {
+ super(client, entityId);
+ /**
+ * @ignore
+ * @internal
+ * ApiClient for {@link LayoutEntitiesController}
+ */
+ _ColumnOrRow_client.set(this, void 0);
+ /**
+ * Retrieves the content array of the ColumnOrRow
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Retrieves the parent ColumnOrRow
+ * const columnOrRow = await stack.getParent();
+ *
+ * // returns [TabStack]
+ * const contentArray = await columnOrRow.getContent();
+ * console.log(`The ColumnOrRow has ${contentArray.length} item(s)`);
+ * ```
+ */
+ this.getContent = async () => {
+ const contentItemEntities = await __classPrivateFieldGet$e(this, _ColumnOrRow_client, "f").getContent(this.entityId);
+ return contentItemEntities.map((entity) => LayoutNode.getEntity(entity, __classPrivateFieldGet$e(this, _ColumnOrRow_client, "f")));
+ };
+ __classPrivateFieldSet$c(this, _ColumnOrRow_client, client, "f");
+ this.type = type;
+ }
+}
+layoutEntities.ColumnOrRow = ColumnOrRow;
+_ColumnOrRow_client = new WeakMap();
+
+var layout_constants = {};
+
+Object.defineProperty(layout_constants, "__esModule", { value: true });
+layout_constants.DEFAULT_LAYOUT_KEY = layout_constants.LAYOUT_CONTROLLER_ID = void 0;
+layout_constants.LAYOUT_CONTROLLER_ID = 'layout-entities';
+// TODO: eventually export this somehow
+layout_constants.DEFAULT_LAYOUT_KEY = '__default__';
+
+var main = {};
+
+Object.defineProperty(main, "__esModule", { value: true });
+main.WebContents = void 0;
+const base_1$k = base;
+class WebContents extends base_1$k.EmitterBase {
+ /**
+ * @param identity The identity of the {@link OpenFin.WebContentsEvents WebContents}.
+ * @param entityType The type of the {@link OpenFin.WebContentsEvents WebContents}.
+ */
+ constructor(wire, identity, entityType) {
+ super(wire, entityType, identity.uuid, identity.name);
+ this.identity = identity;
+ this.entityType = entityType;
+ }
+ /**
+ * Gets a base64 encoded image of all or part of the WebContents.
+ * @param options Options for the capturePage call.
+ *
+ * @example
+ *
+ * View:
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ *
+ * // PNG image of a full visible View
+ * console.log(await view.capturePage());
+ *
+ * // Low-quality JPEG image of a defined visible area of the view
+ * const options = {
+ * area: {
+ * height: 100,
+ * width: 100,
+ * x: 10,
+ * y: 10,
+ * },
+ * format: 'jpg',
+ * quality: 20
+ * }
+ * console.log(await view.capturePage(options));
+ * ```
+ *
+ * Window:
+ * ```js
+ * const wnd = await fin.Window.getCurrent();
+ *
+ * // PNG image of a full visible window
+ * console.log(await wnd.capturePage());
+ *
+ * // Low-quality JPEG image of a defined visible area of the window
+ * const options = {
+ * area: {
+ * height: 100,
+ * width: 100,
+ * x: 10,
+ * y: 10,
+ * },
+ * format: 'jpg',
+ * quality: 20
+ * }
+ * console.log(await wnd.capturePage(options));
+ * ```
+ *
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ capturePage(options) {
+ return this.wire.sendAction('capture-page', { options, ...this.identity }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Executes Javascript on the WebContents, restricted to contents you own or contents owned by
+ * applications you have created.
+ * @param code JavaScript code to be executed on the view.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function executeJavaScript(code) {
+ * const view = await fin.View.wrap({uuid: 'uuid', name: 'view name'});
+ * return await view.executeJavaScript(code);
+ * }
+ *
+ * executeJavaScript(`console.log('Hello, Openfin')`).then(() => console.log('Javascript excuted')).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function executeJavaScript(code) {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.executeJavaScript.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.executeJavaScript(code);
+ * }
+ *
+ * executeJavaScript(`console.log('Hello, Openfin')`).then(() => console.log('Javascript excuted')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ executeJavaScript(code) {
+ return this.wire
+ .sendAction('execute-javascript-in-window', { ...this.identity, code })
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns the zoom level of the WebContents.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function getZoomLevel() {
+ * const view = await fin.View.getCurrent();
+ * return await view.getZoomLevel();
+ * }
+ *
+ * getZoomLevel().then(zoomLevel => console.log(zoomLevel)).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getZoomLevel.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function getZoomLevel() {
+ * const win = await createWin();
+ * return await win.getZoomLevel();
+ * }
+ *
+ * getZoomLevel().then(zoomLevel => console.log(zoomLevel)).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ getZoomLevel() {
+ return this.wire.sendAction('get-zoom-level', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Sets the zoom level of the WebContents.
+ * @param level The zoom level
+ *
+ * @example
+ * View:
+ * ```js
+ * async function setZoomLevel(number) {
+ * const view = await fin.View.getCurrent();
+ * return await view.setZoomLevel(number);
+ * }
+ *
+ * setZoomLevel(4).then(() => console.log('Setting a zoom level')).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.setZoomLevel.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function setZoomLevel(number) {
+ * const win = await createWin();
+ * return await win.setZoomLevel(number);
+ * }
+ *
+ * setZoomLevel(4).then(() => console.log('Setting a zoom level')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ setZoomLevel(level) {
+ return this.wire.sendAction('set-zoom-level', { ...this.identity, level }).then(() => undefined);
+ }
+ /**
+ * Navigates the WebContents to a specified URL.
+ *
+ * Note: The url must contain the protocol prefix such as http:// or https://.
+ * @param url - The URL to navigate the WebContents to.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewName',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * createView()
+ * .then(view => view.navigate('https://example.com'))
+ * .then(() => console.log('navigation complete'))
+ * .catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function navigate() {
+ * const win = await fin.Window.getCurrent();
+ * return await win.navigate('https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.navigate.html');
+ * }
+ * navigate().then(() => console.log('Navigate to tutorial')).catch(err => console.log(err));
+ * ```
+ * @experimental
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ navigate(url) {
+ return this.wire.sendAction('navigate-window', { ...this.identity, url }).then(() => undefined);
+ }
+ /**
+ * Navigates the WebContents back one page.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function navigateBack() {
+ * const view = await fin.View.wrap({ name: 'testapp-view', uuid: 'testapp' });
+ * await view.navigate('https://www.google.com');
+ * return await view.navigateBack();
+ * }
+ * navigateBack().then(() => console.log('Navigated back')).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function navigateBack() {
+ * const win = await fin.Window.wrap({ name: 'testapp', uuid: 'testapp' });
+ * await win.navigate('https://www.google.com');
+ * return await win.navigateBack();
+ * }
+ * navigateBack().then(() => console.log('Navigated back')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ navigateBack() {
+ return this.wire.sendAction('navigate-window-back', { ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Navigates the WebContents forward one page.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function navigateForward() {
+ * const view = await fin.View.getCurrent();
+ * await view.navigate('https://www.google.com');
+ * await view.navigateBack();
+ * return await view.navigateForward();
+ * }
+ * navigateForward().then(() => console.log('Navigated forward')).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function navigateForward() {
+ * const win = await fin.Window.getCurrent();
+ * await win.navigate('https://www.google.com');
+ * await win.navigateBack();
+ * return await win.navigateForward();
+ * }
+ * navigateForward().then(() => console.log('Navigated forward')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async navigateForward() {
+ await this.wire.sendAction('navigate-window-forward', { ...this.identity });
+ }
+ /**
+ * Stops any current navigation the WebContents is performing.
+ *
+ * @example
+ * View:
+ * ```js
+ * async function stopNavigation() {
+ * const view = await fin.View.wrap({ name: 'testapp-view', uuid: 'testapp' });
+ * await view.navigate('https://www.google.com');
+ * return await view.stopNavigation();
+ * }
+ * stopNavigation().then(() => console.log('you shall not navigate')).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function stopNavigation() {
+ * const win = await fin.Window.wrap({ name: 'testapp', uuid: 'testapp' });
+ * await win.navigate('https://www.google.com');
+ * return await win.stopNavigation();
+ * }
+ * stopNavigation().then(() => console.log('you shall not navigate')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ stopNavigation() {
+ return this.wire.sendAction('stop-window-navigation', { ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Reloads the WebContents
+ *
+ * @example
+ * View:
+ * ```js
+ * async function reload() {
+ * const view = await fin.View.getCurrent();
+ * return await view.reload();
+ * }
+ *
+ * reload().then(() => {
+ * console.log('Reloaded view')
+ * }).catch(err => console.log(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function reloadWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.reload.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.reload();
+ * }
+ *
+ * reloadWindow().then(() => {
+ * console.log('Reloaded window')
+ * }).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ reload(ignoreCache = false) {
+ return this.wire
+ .sendAction('reload-window', {
+ ignoreCache,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Prints the WebContents.
+ * @param options Printer Options
+ *
+ * Note: When `silent` is set to `true`, the API will pick the system's default printer if deviceName
+ * is empty and the default settings for printing.
+ *
+ * Use the CSS style `page-break-before: always;` to force print to a new page.
+ *
+ * @example
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ *
+ * view.print({ silent: false, deviceName: 'system-printer-name' }).then(() => {
+ * console.log('print call has been sent to the system');
+ * });
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ print(options = {}) {
+ return this.wire.sendAction('print', { ...this.identity, options }).then(() => undefined);
+ }
+ /**
+ * Find and highlight text on a page.
+ * @param searchTerm Term to find in page
+ * @param options Search options
+ *
+ * Note: By default, each subsequent call will highlight the next text that matches the search term.
+ *
+ * Returns a promise with the results for the request. By subscribing to the
+ * found-in-page event, you can get the results of this call as well.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ *
+ * //By subscribing to the 'found in page' event we can get the results of each findInPage call made.
+ * view.addListener('found-in-page', (event) => {
+ * console.log(event);
+ * });
+ *
+ * // The promise also returns the results for the request
+ * view.findInPage('a').then((result) => {
+ * console.log(result)
+ * });
+ * ```
+ *
+ * Window:
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * //By subscribing to the 'found in page' event we can get the results of each findInPage call made.
+ * win.addListener('found-in-page', (event) => {
+ * console.log(event);
+ * });
+ *
+ * // The promise also returns the results for the request
+ * win.findInPage('a').then((result) => {
+ * console.log(result)
+ * });
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ findInPage(searchTerm, options) {
+ return this.wire
+ .sendAction('find-in-page', { ...this.identity, searchTerm, options })
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * Stop a {@link View#findInPage findInPage} call by specifying any of these actions:
+ *
+ * * clearSelection - Clear the selection.
+ * * keepSelection - Translate the selection into a normal selection.
+ * * activateSelection - Focus and click the selection node.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ *
+ * view.addListener('found-in-page', (event) => {
+ * setTimeout(() => {
+ * view.stopFindInPage('clearSelection');
+ * }, 5000);
+ * });
+ *
+ * view.findInPage('a').then(results => {
+ * console.log(results);
+ * });
+ * ```
+ *
+ * Window:
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * win.addListener('found-in-page', (event) => {
+ * setTimeout(() => {
+ * win.stopFindInPage('clearSelection');
+ * }, 5000);
+ * });
+ *
+ * win.findInPage('a').then(results => {
+ * console.log(results);
+ * });
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ stopFindInPage(action) {
+ return this.wire.sendAction('stop-find-in-page', { ...this.identity, action }).then(() => undefined);
+ }
+ /**
+ * Returns an array with all system printers
+ * @deprecated use System.getPrinters instead
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = fin.View.getCurrentSync();
+ *
+ * view.getPrinters()
+ * .then((printers) => {
+ * printers.forEach((printer) => {
+ * if (printer.isDefault) {
+ * console.log(printer);
+ * }
+ * });
+ * })
+ * .catch((err) => {
+ * console.log(err);
+ * });
+ * ```
+ *
+ * Window:
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * win.getPrinters()
+ * .then((printers) => {
+ * printers.forEach((printer) => {
+ * if (printer.isDefault) {
+ * console.log(printer);
+ * }
+ * });
+ * })
+ * .catch((err) => {
+ * console.log(err);
+ * });
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ getPrinters() {
+ return this.wire.sendAction('get-printers', { ...this.identity }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Gives focus to the WebContents.
+ *
+ * @example
+ * ```js
+ * async function focusWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.focus.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.focus();
+ * }
+ *
+ * focusWindow().then(() => console.log('Window focused')).catch(err => console.log(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async focus({ emitSynthFocused } = { emitSynthFocused: true }) {
+ await this.wire.sendAction('focus-window', { emitSynthFocused, ...this.identity });
+ }
+ /**
+ * Shows the Chromium Developer Tools
+ *
+ * @example
+ * View:
+ * ```js
+ * async function showDeveloperTools() {
+ * const view = await fin.View.getCurrent();
+ * return view.showDeveloperTools();
+ * }
+ *
+ * showDevelopertools()
+ * .then(() => console.log('Showing dev tools'))
+ * .catch(err => console.error(err));
+ * ```
+ *
+ * Window:
+ * ```js
+ * async function showDeveloperTools() {
+ * const win = await fin.Window.getCurrent();
+ * return win.showDeveloperTools();
+ * }
+ *
+ * showDevelopertools()
+ * .then(() => console.log('Showing dev tools'))
+ * .catch(err => console.error(err));
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async showDeveloperTools() {
+ // Note this hits the system action map in core state for legacy reasons.
+ await this.wire.sendAction('show-developer-tools', this.identity);
+ }
+ /**
+ * Retrieves the process information associated with a WebContents.
+ *
+ * Note: This includes any iframes associated with the WebContents
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = await fin.View.getCurrent();
+ * const processInfo = await view.getProcessInfo();
+ * ```
+ *
+ * Window:
+ * ```js
+ * const win = await fin.Window.getCurrent();
+ * const processInfo = await win.getProcessInfo();
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async getProcessInfo() {
+ const { payload: { data } } = await this.wire.sendAction('get-process-info', this.identity);
+ return data;
+ }
+ /**
+ * Retrieves information on all Shared Workers.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = await fin.View.create({
+ * name: 'viewName',
+ * target: fin.me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ *
+ * await view.navigate('http://mdn.github.io/simple-shared-worker/index2.html');
+ *
+ * const sharedWorkers = await view.getSharedWorkers();
+ * ```
+ *
+ * Window:
+ * ```js
+ * const winOption = {
+ * name:'child',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'http://mdn.github.io/simple-shared-worker/index2.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * const win = await fin.Window.create(winOption);
+ * const sharedWorkers = await win.getSharedWorkers();
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async getSharedWorkers() {
+ return this.wire.sendAction('get-shared-workers', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Opens the developer tools for the shared worker context.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = await fin.View.create({
+ * name: 'viewName',
+ * target: fin.me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ *
+ * await view.navigate('http://mdn.github.io/simple-shared-worker/index2.html');
+ *
+ * await view.inspectSharedWorker();
+ * ```
+ *
+ * Example:
+ * ```js
+ * const winOption = {
+ * name:'child',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'http://mdn.github.io/simple-shared-worker/index2.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * const win = await fin.Window.create(winOption);
+ * await win.inspectSharedWorker();
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async inspectSharedWorker() {
+ await this.wire.sendAction('inspect-shared-worker', { ...this.identity });
+ }
+ /**
+ * Inspects the shared worker based on its ID.
+ * @param workerId - The id of the shared worker.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = await fin.View.create({
+ * name: 'viewName',
+ * target: fin.me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ *
+ * await view.navigate('http://mdn.github.io/simple-shared-worker/index2.html');
+ *
+ * const sharedWorkers = await view.getSharedWorkers();
+ * await view.inspectSharedWorkerById(sharedWorkers[0].id);
+ * ```
+ *
+ * Window:
+ * ```js
+ * const winOption = {
+ * name:'child',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'http://mdn.github.io/simple-shared-worker/index2.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * const win = await fin.Window.create(winOption);
+ * const sharedWorkers = await win.getSharedWorkers();
+ * await win.inspectSharedWorkerById(sharedWorkers[0].id);
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async inspectSharedWorkerById(workerId) {
+ await this.wire.sendAction('inspect-shared-worker-by-id', { ...this.identity, workerId });
+ }
+ /**
+ * Opens the developer tools for the service worker context.
+ *
+ * @example
+ * View:
+ * ```js
+ * const view = await fin.View.create({
+ * name: 'viewName',
+ * target: fin.me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ *
+ * await view.navigate('http://googlechrome.github.io/samples/service-worker/basic/index.html');
+ *
+ * await view.inspectServiceWorker();
+ * ```
+ *
+ * Window:
+ * ```js
+ * const winOption = {
+ * name:'child',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'http://googlechrome.github.io/samples/service-worker/basic/index.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * const win = await fin.Window.create(winOption);
+ * await win.inspectServiceWorker();
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async inspectServiceWorker() {
+ await this.wire.sendAction('inspect-service-worker', { ...this.identity });
+ }
+ /**
+ * Shows a popup window.
+ *
+ * Note: If this WebContents is a view and its attached window has a popup open, this will close it.
+ *
+ * Shows a popup window. Including a `name` in `options` will attempt to show an existing window as a popup, if
+ * that window doesn't exist or no `name` is included a window will be created. If the caller view or the caller
+ * view's parent window currently has a popup window open, calling `showPopupWindow` again will dismiss the currently
+ * open popup window before showing the new popup window. Also, if the caller view is destroyed or detached, the popup
+ * will be dismissed.
+ *
+ * Note: in the case where the window being shown as a popup needs to be created, it is a child of the caller view's parent window.
+ *
+ * @example
+ *
+ * Create and show a single-use popup window that returns a single result to the caller. `initialOptions` allows
+ * us to pass window options to the popup window that will be created. `resultDispatchBehavior: 'close'` ensures
+ * that once the popup window calls `dispatchPopupResult` it is closed. `blurBehavior: 'close'` will yield a dismissed
+ * result should the popup window lose focus.
+ *
+ * ```js
+ * const result = await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: false
+ * },
+ * url: '',
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'close',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0
+ * });
+ * ```
+ *
+ * Same as above but using an existing window as a popup by referencing its `name`:
+ *
+ * Note: if a window with the `name` provided doesn't exist, it will be created.
+ *
+ * ```js
+ * const result = await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: true
+ * },
+ * name: 'my-popup', // shows the 'my-popup' window if it exists, otherwise creates it
+ * url: '', // navigates to this url if it doesn't match the location.href of the 'my-popup' window
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'close',
+ * focus: true,
+ * hideOnClose: true, // persist window on 'dismissed' result, alternatively change onResultDispatch and blurBehavior to 'hide'
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0
+ * });
+ * ```
+ *
+ * Create and show a popup window that is able to return multiple results to the caller via an `onPopupResult` callback. Each
+ * time the popup window calls `dispatchPopupResult`, the callback will be executed on the result. Once the popup window is
+ * closed or hidden, the `showPopupWindow` promise will resolve with a `dismissed` result that will include the most recently
+ * dispatched result as `lastDispatchResult`:
+ *
+ * ```js
+ * const popupResultCallback = (payload) => {
+ * if (payload.result === 'clicked') {
+ * if (payload.data.topic === 'color-changed') {
+ * // do something like
+ * // setColor(payload.data.value);
+ * }
+ * }
+ * };
+ *
+ * await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: false
+ * },
+ * url: '',
+ * resultDispatchBehavior: 'none',
+ * blurBehavior: 'close',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0,
+ * onPopupResult: popupResultCallback
+ * });
+ * ```
+ *
+ * Same as above but using an existing window as a popup:
+ *
+ * ```js
+ * const popupResultCallback = (payload) => {
+ * if (payload.result === 'clicked') {
+ * if (payload.data.topic === 'color-changed') {
+ * // do something like
+ * // setColor(payload.data.value);
+ * }
+ * }
+ * };
+ *
+ * await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: false
+ * },
+ * name: 'my-popup', // shows the 'my-popup' window if it exists, otherwise creates it
+ * url: '', // navigates to this url if it doesn't match the location.href of the 'my-popup' window
+ * resultDispatchBehavior: 'none',
+ * blurBehavior: 'hide',
+ * focus: true,
+ * hideOnClose: true, // we can just use this or we can change blurBehavior to 'hide'
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0,
+ * onPopupResult: popupResultCallback
+ * });
+ * ```
+ *
+ * Create or show a popup window that disables user movement (positioning and resizing) in the caller
+ * view's parent window by using `blurBehavior: 'modal'`:
+ *
+ * ```js
+ * const result = await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: false
+ * },
+ * url: '',
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'modal',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0
+ * });
+ * ```
+ *
+ * Create a popup window as a modal:
+ *
+ * Note: The only way to ensure true modal behavior is to create the window being shown as a popup with a
+ * `modalParentIdentity` that uses the caller view's parent window identity.
+ *
+ * ```js
+ * const result = await fin.me.showPopupWindow({
+ * initialOptions: {
+ * frame: false,
+ * modalParentIdentity: fin.me.identity
+ * },
+ * url: '',
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'modal',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0
+ * });
+ * ```
+ *
+ * Pass data to a popup window that is available when the popup is shown.
+ *
+ * Note: this is just one example for a use of `additionalOptions`, it can be used to update any updatable
+ * window options when creating or showing an existing window as a popup.
+ *
+ * ```js
+ * const result = await fin.me.showPopupWindow({
+ * additionalOptions: {
+ * customData: {
+ * foo: 'bar'
+ * }
+ * },
+ * url: '',
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'close',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0
+ * });
+ *
+ * // Access from the popup window context like so:
+ * const { customData } = await fin.me.getOptions();
+ * const { foo } = customData;
+ * ```
+ *
+ * Execute a callback on the popup's OpenFin window when the popup is shown:
+ *
+ * ```js
+ * const popupWindowCallback = async (win) => {
+ * await win.flash();
+ * };
+ *
+ * const result = await fin.me.showPopupWindow({
+ * url: '',
+ * resultDispatchBehavior: 'close',
+ * blurBehavior: 'close',
+ * focus: true,
+ * height: 300,
+ * width: 300,
+ * x: 0,
+ * y: 0,
+ * onPopupReady: popupWindowCallback;
+ * });
+ * ```
+ * @remarks
+ * `WebContents` refers to shared functionality between {@link OpenFin.Window} and {@link OpenFin.View}.
+ * We do not expose an explicit superclass for this functionality, but it does have its own
+ * {@link OpenFin.WebContentsEvents event namespace}.
+ */
+ async showPopupWindow(options) {
+ this.wire.sendAction(`${this.entityType}-show-popup-window`, this.identity).catch(() => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ if (options?.onPopupReady) {
+ const readyListener = async ({ popupName }) => {
+ try {
+ const popupWindow = this.fin.Window.wrapSync({ uuid: this.fin.me.uuid, name: popupName });
+ await options.onPopupReady(popupWindow);
+ }
+ catch (error) {
+ throw new Error(`Something went wrong during onPopupReady execution: ${error}`);
+ }
+ };
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ await this.once('popup-ready', readyListener);
+ }
+ const { payload: tryCreatePayload } = await this.wire.sendAction('try-create-popup-window', {
+ options: {
+ ...options,
+ // Internal use only.
+ // @ts-expect-error
+ hasResultCallback: !!options?.onPopupResult,
+ hasReadyCallback: !!options?.onPopupReady
+ },
+ ...this.identity
+ });
+ const { data: { willOpen, options: popupOptions } } = tryCreatePayload;
+ if (willOpen) {
+ // Solve the issue where Interop in a popup window with non cross-origin url is not working(core-1076).
+ await this.fin.Window.create(popupOptions.initialOptions);
+ }
+ const normalizePopupResult = (payload) => {
+ const { name, uuid, result, data } = payload;
+ const popupResult = {
+ identity: {
+ name,
+ uuid
+ },
+ result
+ };
+ if (data) {
+ popupResult.data = data;
+ }
+ return popupResult;
+ };
+ if (options?.onPopupResult) {
+ const dispatchResultListener = async (payload) => {
+ await options.onPopupResult(normalizePopupResult(payload));
+ };
+ const teardownListener = async () => {
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ await this.removeListener('popup-result', dispatchResultListener);
+ };
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ await this.on('popup-result', dispatchResultListener);
+ // TODO: fix typing (internal)
+ // hilariously this does not need a ts-expect-error - this is gap in type soundness
+ // should investigate - probably due to `teardownListener` taking a void argument
+ // which might play nicely with the `never` type? huh...
+ await this.once('popup-teardown', teardownListener);
+ }
+ const { payload } = await this.wire.sendAction('show-popup-window', {
+ options: popupOptions,
+ ...this.identity
+ });
+ return payload.data;
+ }
+}
+main.WebContents = WebContents;
+
+var hasRequiredInstance$2;
+
+function requireInstance$2 () {
+ if (hasRequiredInstance$2) return Instance$5;
+ hasRequiredInstance$2 = 1;
+ var __classPrivateFieldGet = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+ };
+ var _View_providerChannelClient;
+ Object.defineProperty(Instance$5, "__esModule", { value: true });
+ Instance$5.View = void 0;
+ const transport_errors_1 = transportErrors;
+ const lazy_1 = lazy;
+ const layout_entities_1 = layoutEntities;
+ const layout_constants_1 = layout_constants;
+ const main_1 = main;
+ const window_1 = requireWindow();
+ /**
+ * @PORTED
+ * @typedef {object} View~options
+ * @summary View creation options.
+ * @desc This is the options object required by {@link View.create View.create}.
+ *
+ * Note that `name` and `target` are the only required properties — albeit the `url` property is usually provided as well
+ * (defaults to `"about:blank"` when omitted).
+ *
+ * @property {object} [experimental]
+ * Configurations for API injection.
+ *
+ * @property {boolean} [experimental.childWindows] Configure if the runtime should enable child windows for views.
+ *
+ * @property {object} [accelerator]
+ * Enable keyboard shortcuts for devtools, zoom, reload, and reload ignoring cache.
+ *
+ * @property {boolean} [accelerator.devtools=false]
+ * If `true`, enables the devtools keyboard shortcut:
+ * `Ctrl` + `Shift` + `I` _(Toggles Devtools)_
+ *
+ * @property {boolean} [accelerator.reload=false]
+ * If `true`, enables the reload keyboard shortcuts:
+ * `Ctrl` + `R` _(Windows)_
+ * `F5` _(Windows)_
+ * `Command` + `R` _(Mac)_
+ *
+ * @property {boolean} [accelerator.reloadIgnoringCache=false]
+ * If `true`, enables the reload-from-source keyboard shortcuts:
+ * `Ctrl` + `Shift` + `R` _(Windows)_
+ * `Shift` + `F5` _(Windows)_
+ * `Command` + `Shift` + `R` _(Mac)_
+ *
+ * @property {boolean} [accelerator.zoom=false]
+ * If `true`, enables the zoom keyboard shortcuts:
+ * `Ctrl` + `+` _(Zoom In)_
+ * `Ctrl` + `Shift` + `+` _(Zoom In)_
+ * `Ctrl` + `NumPad+` _(Zoom In)_
+ * `Ctrl` + `-` _(Zoom Out)_
+ * `Ctrl` + `Shift` + `-` _(Zoom Out)_
+ * `Ctrl` + `NumPad-` _(Zoom Out)_
+ * `Ctrl` + `Scroll` _(Zoom In & Out)_
+ * `Ctrl` + `0` _(Restore to 100%)_
+ *
+ * @property {object} [api]
+ * Configurations for API injection.
+ *
+ * @property {object} [api.iframe] Configure if the the API should be injected into iframes based on domain.
+ *
+ * @property {boolean} [api.iframe.crossOriginInjection=false] Controls if the `fin` API object is present for cross origin iframes.
+ * @property {boolean} [api.iframe.sameOriginInjection=true] Controls if the `fin` API object is present for same origin iframes.
+ *
+ * @property {string} [autoplayPolicy="no-user-gesture-required"]
+ * Autoplay policy to apply to content in the window, can be
+ * `no-user-gesture-required`, `user-gesture-required`,
+ * `document-user-activation-required`. Defaults to `no-user-gesture-required`.
+ *
+ * @property {object} [autoResize] AutoResize options
+ *
+ * @property {object} [bounds] initial bounds given relative to the window.
+ *
+ * @property {string} [backgroundColor="#FFF"] - _Updatable._
+ * The view’s _backfill_ color as a hexadecimal value. Not to be confused with the content background color
+ * (`document.body.style.backgroundColor`),
+ * this color briefly fills a view’s (a) content area before its content is loaded as well as (b) newly exposed
+ * areas when growing a window. Setting
+ * this value to the anticipated content background color can help improve user experience.
+ * Default is white.
+ *
+ * @property {object} [contentNavigation]
+ * Restrict navigation to URLs that match an allowed pattern.
+ * In the lack of an allowlist, navigation to URLs that match a denied pattern would be prohibited.
+ * See [here](https://developer.chrome.com/extensions/match_patterns) for more details.
+ * @property {string[]} [contentNavigation.allowlist=[]] List of allowed URLs.
+ * @property {string[]} [contentNavigation.denylist=[]] List of denied URLs.
+ *
+ * @property {object} [contentRedirect]
+ * Restrict redirects to URLs that match an allowed pattern.
+ * In the lack of an allowlist, redirects to URLs that match a denied pattern would be prohibited.
+ * See [here](https://developer.chrome.com/extensions/match_patterns) for more details.
+ * @property {string[]} [contentRedirect.allowlist=[]] List of allowed URLs.
+ * @property {string[]} [contentRedirect.denylist=[]] List of denied URLs.
+ *
+ * @property {object} [contextMenuSettings] - _Updatable._
+ * Deprecated - superseded by {@link contextMenuOptions}, which offers a larger feature-set and cleaner syntax.
+ * Configure the context menu when right-clicking on a view.
+ * @property {boolean} [contextMenuSettings.enable=true] Should the context menu display on right click.
+ * @property {boolean} [contextMenuSettings.devtools=true] Should the context menu contain a button for opening devtools.
+ * @property {boolean} [contextMenuSettings.reload=true] Should the context menu contain a button for reloading the page.
+ *
+ * @property {object} [contextMenuOptions] - _Updatable._
+ * Configure the context menu when right-clicking on a view. Supported menu items:
+ * 'separator'
+ * 'cut'
+ * 'copy'
+ * 'copyImage',
+ * 'paste'
+ * 'spellCheck'
+ * 'inspect'
+ * 'reload'
+ * 'navigateForward'
+ * 'navigateBack'
+ * 'print'
+ * @property {boolean} [contextMenuOptions.enabled = true] Should the context menu display on right click.
+ * @property {string[]} [contextMenuOptions.template=[]] List of context menu items to display on right-click.
+ *
+ * @property {any} [customData=""] - _Updatable._
+ * A field that the user can attach serializable data to be ferried around with the view options.
+ * _When omitted, the default value of this property is the empty string (`""`)._
+ *
+ * @property {any} [customContext=""] - _Updatable._
+ * A field that the user can use to attach serializable data that will be saved when {@link Platform#getSnapshot Platform.getSnapshot}
+ * is called.
+ * When omitted, the default value of this property is the empty string (`""`).
+ * As opposed to customData, this is meant for frequent updates and sharing with other contexts. [Example]{@tutorial customContext}
+ *
+ * @property {object[]} [hotkeys=[]] - _Updatable._
+ * Defines the list of hotkeys that will be emitted as a `hotkey` event on the view. For usage example see [example]{@tutorial hotkeys}.
+ * Within Platform, OpenFin also implements a set of pre-defined actions called
+ * [keyboard commands]{@link https://developers.openfin.co/docs/platform-api#section-5-3-using-keyboard-commands}
+ * that can be assigned to a specific hotkey in the platform manifest.
+ * @property {string} hotkeys.keys The key combination of the hotkey, i.e. "Ctrl+T"
+ * @property {boolean} [hotkeys.preventDefault=false] preventDefault will prevent the page keydown/keyup events from being emitted.
+ *
+ * @property {boolean} [isClosable=true] **Platforms Only.** If false, the view will be persistent and can't be closed through
+ * either UI or `Platform.closeView`. Note that the view will still be closed if the host window is closed or
+ * if the view isn't part of the new layout when running `Layout.replace`.
+ *
+ * @property {string} name
+ * The name of the view.
+ *
+ * @property {boolean} [detachOnClose=false] - _Updatable._
+ * Platforms Only. If true, will hide and detach the View from the window for later use instead of closing,
+ * allowing the state of the View to be saved and the View to be immediately shown in a new Layout.
+ *
+ * @property {string} [manifestUrl] **Platforms Only.** Url to a manifest that contains View Options. Properties other than manifestUrl can still be used
+ * but the properties in the manifest will take precedence if there is any collision.
+ *
+ * @property {preloadScript[]} [preloadScripts] - _Inheritable_
+ * A list of scripts that are eval'ed before other scripts in the page. When omitted, _inherits_
+ * from the parent application.
+ *
+ * @property {boolean} [preventDragOut=false] **Platforms Only.** If true, the tab of the view can't be dragged out of its host window.
+ *
+ * @property {string} [processAffinity=]
+ * A string to attempt to group renderers together. Will only be used if pages are on the same origin.
+ *
+ * @property {boolean} [spellCheck=false]
+ * Enable spell check in input text fields for the view.
+ *
+ * @property {Identity} [target]
+ * The identity of the window this view should be attached to.
+ *
+ * @property {string} [url="about:blank"]
+ * The URL of the view.
+ *
+ * @property {string} [uuid=]
+ * The `uuid` of the application, unique within the set of all `Application`s running in OpenFin Runtime.
+ * If omitted, defaults to the `uuid` of the application spawning the view.
+ * If given, must match the `uuid` of the application spawning the view.
+ * In other words, the application's `uuid` is the only acceptable value, but is the default, so there's
+ * really no need to provide it.
+ */
+ /**
+ * A View can be used to embed additional web content into a Window.
+ * It is like a child window, except it is positioned relative to its owning window.
+ * It has the ability to listen for {@link OpenFin.ViewEvents View-specific events}.
+ *
+ * By default, a View will try to share the same renderer process as other Views owned by its parent Application.
+ * To change that behavior, see the processAffinity {@link OpenFin.ViewOptions view option}.
+ *
+ * A View's lifecycle is tied to its owning window and can be re-attached to a different window at any point during its lifecycle.
+ */
+ class View extends main_1.WebContents {
+ /**
+ * @internal
+ */
+ constructor(wire, identity) {
+ super(wire, identity, 'view');
+ this.identity = identity;
+ _View_providerChannelClient.set(this, new lazy_1.Lazy(() => {
+ const platform = this.fin.Platform.wrapSync(this.identity);
+ return platform.getClient();
+ }));
+ /**
+ * Attaches the current view to the given window identity.
+ * Identity must be the identity of a window in the same application.
+ * This detaches the view from its current window, and sets the view to be destroyed when its new window closes.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameAttach',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function attachView() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * const winOption = {
+ * name:'winOptionName',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.create.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * const newWindow = await fin.Window.create(winOption);
+ * view.attach(newWindow.identity);
+ * }
+ *
+ * attachView()
+ * .then(() => console.log('View attached to new window.'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.attach = async (target) => {
+ await this.wire.sendAction('attach-view', { target, ...this.identity });
+ };
+ /**
+ * Destroys the current view
+ *
+ * @example
+ * ```js
+ * const view = fin.View.wrapSync({ uuid: 'viewUuid', name: 'viewName' });
+ * view.destroy();
+ * ```
+ * @experimental
+ */
+ this.destroy = async () => {
+ await this.wire.sendAction('destroy-view', { ...this.identity });
+ };
+ /**
+ * Shows the current view if it is currently hidden.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameShow',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function hideAndShowView() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url option.');
+ *
+ * await view.hide();
+ * console.log("View hidden.");
+ *
+ * view.show();
+ * console.log("View shown.");
+ * }
+ *
+ * hideAndShowView()
+ * .then(() => console.log('View hidden and shown.'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.show = async () => {
+ await this.wire.sendAction('show-view', { ...this.identity });
+ };
+ /**
+ * Sets the bounds (top, left, width, height) of the view relative to its window and shows it if it is hidden.
+ * This method ensures the view is both positioned and showing. It will reposition a visible view and both show and reposition a hidden view.
+ *
+ * @remarks View position is relative to the bounds of the window.
+ * ({top: 0, left: 0} represents the top left corner of the window)
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameSetBounds',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function showViewAt() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * await view.showAt({
+ * top: 100,
+ * left: 100,
+ * width: 300,
+ * height: 300
+ * });
+ * }
+ *
+ * showViewAt()
+ * .then(() => console.log('View set to new bounds and shown.'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.showAt = async (bounds) => {
+ await this.wire.sendAction('show-view-at', { bounds, ...this.identity });
+ };
+ /**
+ * Hides the current view if it is currently visible.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameHide',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function hideView() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * await view.hide();
+ * }
+ *
+ * hideView()
+ * .then(() => console.log('View hidden.'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.hide = async () => {
+ await this.wire.sendAction('hide-view', { ...this.identity });
+ };
+ /**
+ * Sets the bounds (top, left, width, height) of the view relative to its window.
+ *
+ * @remarks View position is relative to the bounds of the window.
+ * ({top: 0, left: 0} represents the top left corner of the window)
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameSetBounds',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function setViewBounds() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * await view.setBounds({
+ * top: 100,
+ * left: 100,
+ * width: 300,
+ * height: 300
+ * });
+ * }
+ *
+ * setViewBounds()
+ * .then(() => console.log('View set to new bounds.'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.setBounds = async (bounds) => {
+ await this.wire.sendAction('set-view-bounds', { bounds, ...this.identity });
+ };
+ /**
+ * Gets the bounds (top, left, width, height) of the view relative to its window.
+ *
+ * @remarks View position is relative to the bounds of the window.
+ * ({top: 0, left: 0} represents the top left corner of the window)
+ *
+ * @example
+ * ```js
+ * const view = await fin.View.create({
+ * name: 'viewNameSetBounds',
+ * target: fin.me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ *
+ * await view.navigate('https://google.com');
+ *
+ * await view.setBounds({
+ * top: 100,
+ * left: 100,
+ * width: 300,
+ * height: 300
+ * });
+ *
+ * console.log(await view.getBounds());
+ * ```
+ * @experimental
+ */
+ this.getBounds = async () => {
+ const ack = await this.wire.sendAction('get-view-bounds', { ...this.identity });
+ return ack.payload.data;
+ };
+ /**
+ * Gets the View's info.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameGetInfo',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function getViewInfo() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * return view.getInfo();
+ * }
+ *
+ * getViewInfo()
+ * .then((info) => console.log('View info fetched.', info))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.getInfo = async () => {
+ const ack = await this.wire.sendAction('get-view-info', { ...this.identity });
+ return ack.payload.data;
+ };
+ /**
+ * Retrieves the layout for the window the view is attached to.
+ *
+ * @example
+ * ```js
+ * //get the current View
+ * const view = await fin.View.getCurrent();
+ *
+ * //get a reference to the Layout for the Window the view is part of
+ * const layout = await view.getParentLayout();
+ * ```
+ * @experimental
+ */
+ this.getParentLayout = async () => {
+ this.wire.sendAction('view-get-parent-layout', { ...this.identity }).catch(() => {
+ // don't expose
+ });
+ const layoutWindow = await this.getCurrentWindow();
+ try {
+ const providerChannelClient = await __classPrivateFieldGet(this, _View_providerChannelClient, "f").getValue();
+ const client = await layout_entities_1.LayoutNode.newLayoutEntitiesClient(providerChannelClient, layout_constants_1.LAYOUT_CONTROLLER_ID, layoutWindow.identity);
+ const layoutIdentity = await client.getLayoutIdentityForViewOrThrow(this.identity);
+ return this.fin.Platform.Layout.wrap(layoutIdentity);
+ }
+ catch (e) {
+ const allowedErrors = [
+ 'No action registered at target for',
+ 'getLayoutIdentityForViewOrThrow is not a function'
+ ];
+ if (!allowedErrors.some((m) => e.message.includes(m))) {
+ throw e;
+ }
+ // fallback logic for missing endpoint
+ return this.fin.Platform.Layout.wrap(layoutWindow.identity);
+ }
+ };
+ /**
+ * Gets the View's options.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * name: 'viewNameGetOptions',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function getViewOptions() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url.');
+ *
+ * const me = await fin.Window.getCurrent();
+ * view = fin.View.wrapSync({ uuid: me.identity.uuid, name: 'viewNameGetOptions' });
+ * return view.getOptions();
+ * }
+ *
+ * getViewOptions()
+ * .then((info) => console.log('View options fetched.', info))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.getOptions = async () => {
+ return this.wire.sendAction('get-view-options', { ...this.identity }).then(({ payload }) => payload.data);
+ };
+ /**
+ * Updates the view's options.
+ *
+ * @example
+ * ```js
+ * let view;
+ * async function createView() {
+ * const me = await fin.Window.getCurrent();
+ * return fin.View.create({
+ * url: 'https://google.com',
+ * name: 'viewNameUpdateOptions',
+ * target: me.identity,
+ * bounds: {top: 10, left: 10, width: 200, height: 200}
+ * });
+ * }
+ *
+ * async function updateViewOptions() {
+ * view = await createView();
+ * console.log('View created.');
+ *
+ * await view.navigate('https://google.com');
+ * console.log('View navigated to given url option.');
+ *
+ * const newOptions = { autoResize: {
+ * width: true,
+ * horizontal: true
+ * }};
+ * return view.updateOptions(newOptions);
+ * }
+ *
+ * updateViewOptions()
+ * .then(payload => console.log('View options updated: ', payload))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ this.updateOptions = async (options) => {
+ return this.wire.sendAction('update-view-options', { options, ...this.identity }).then(() => undefined);
+ };
+ /**
+ * Retrieves the window the view is currently attached to.
+ *
+ * @example
+ * ```js
+ * const view = fin.View.wrapSync({ uuid: 'viewUuid', name: 'viewName' });
+ * view.getCurrentWindow()
+ * .then(win => console.log('current window', win))
+ * .catch(err => console.log(err));)
+ * ```
+ * @experimental
+ */
+ this.getCurrentWindow = async () => {
+ const { payload: { data } } = await this.wire.sendAction('get-view-window', { ...this.identity });
+ return new window_1._Window(this.wire, data);
+ };
+ /**
+ * Retrieves the current {@link OpenFin.TabStack} of the view if it belongs to one.
+ * @returns this view belongs to.
+ * @throws if this view does not belong to a TabStack or if the window has been destroyed.
+ * @example
+ * ```js
+ * if (!fin.me.isView) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * const stack = await fin.me.getCurrentStack();
+ * // Alternatively, you can wrap any view and get the stack from there
+ * // const viewFromSomewhere = fin.View.wrapSync(someView.identity);
+ * // const stack = await viewFromSomewhere.getCurrentStack();
+ * const views = await stack.getViews();
+ * console.log(`Stack contains ${views.length} view(s)`);
+ * ```
+ */
+ this.getCurrentStack = async () => {
+ this.wire.sendAction('view-get-current-stack').catch(() => {
+ // don't expose
+ });
+ try {
+ const layoutWindow = await this.getCurrentWindow();
+ const providerChannelClient = await __classPrivateFieldGet(this, _View_providerChannelClient, "f").getValue();
+ const client = await layout_entities_1.LayoutNode.newLayoutEntitiesClient(providerChannelClient, layout_constants_1.LAYOUT_CONTROLLER_ID, layoutWindow.identity);
+ const stackDefinition = (await client.getStackByView(this.identity));
+ return layout_entities_1.LayoutNode.getEntity(stackDefinition, client);
+ }
+ catch (error) {
+ throw new transport_errors_1.RuntimeError({ reason: 'This view does not belong to a stack.', error });
+ }
+ };
+ /**
+ * Triggers the before-unload handler for the View, if one is set.
+ *
+ * @remarks Returns `true` if the handler is trying to prevent the View from unloading, and `false` if it isn't.
+ * Only enabled when setting enableBeforeUnload: true in your View options. If this option is not enabled it will
+ * always return false.
+ *
+ * This method is used internally by the Platform Provider to determine the status of each before unload handler in Views when closing the Window.
+ *
+ * @example
+ *
+ * ```js
+ * // from inside a View context
+ * const unloadPrevented = await fin.me.triggerBeforeUnload();
+ * ```
+ *
+ * @experimental
+ */
+ this.triggerBeforeUnload = async () => {
+ const message = await this.wire.sendAction('trigger-before-unload', { ...this.identity });
+ return message.payload.data;
+ };
+ /**
+ * **NOTE**: Internal use only.
+ * Attaches this view to an HTML element in the current context. The view will resize responsively when the element bounds change.
+ *
+ * **Known issue**: View.bindToElement does not track position changes, if the element has fixed px width and height values it is possible for the view to not update responsively.
+ *
+ * **Known issue**: When View.bindToElement is used on a element that takes up the entire page in a platform window, the bound view will not respond responsively when the window is resized to be smaller.
+ *
+ * @param element - HTML element to attach the view to.
+ * @returns - Cleanup function that will disconnect the element resize observer.
+ * @internal
+ * @experimental
+ * @remarks View will resize accordingly when the element is resized. If the element is repositioned in the DOM the view will not be repositioned, to handle this case call `bindToElement` again once the element changes position.
+ *
+ * @example
+ * ```html
+ *
+ *
+ * ```
+ */
+ this.bindToElement = async (element) => {
+ if (!element) {
+ throw new Error('Element not found.');
+ }
+ const onChange = async (bounds) => this.setBounds(bounds);
+ return this.wire.environment.observeBounds(element, onChange);
+ };
+ }
+ /**
+ * Focuses the view
+ *
+ * @example
+ * ```js
+ * const view = fin.View.wrapSync({ uuid: 'viewUuid', name: 'viewName' });
+ * await view.focus();
+ * // do things with the focused view
+ * ```
+ * @experimental
+ */
+ async focus({ emitSynthFocused } = { emitSynthFocused: true }) {
+ const win = await this.getCurrentWindow();
+ await win.focusedWebViewWasChanged();
+ await super.focus({ emitSynthFocused });
+ }
+ }
+ Instance$5.View = View;
+ _View_providerChannelClient = new WeakMap();
+ return Instance$5;
+}
+
+var hasRequiredView;
+
+function requireView () {
+ if (hasRequiredView) return view;
+ hasRequiredView = 1;
+ (function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ /**
+ * Entry points for the OpenFin `View` API (`fin.View`).
+ *
+ * * {@link ViewModule} contains static members of the `View` API, accessible through `fin.View`.
+ * * {@link View} describes an instance of an OpenFin View, e.g. as returned by `fin.View.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ */
+ __exportStar(requireFactory$3(), exports);
+ __exportStar(requireInstance$2(), exports);
+ } (view));
+ return view;
+}
+
+var hasRequiredInstance$1;
+
+function requireInstance$1 () {
+ if (hasRequiredInstance$1) return Instance$6;
+ hasRequiredInstance$1 = 1;
+ Object.defineProperty(Instance$6, "__esModule", { value: true });
+ Instance$6.Application = void 0;
+ /* eslint-disable import/prefer-default-export */
+ const base_1 = base;
+ const window_1 = requireWindow();
+ const view_1 = requireView();
+ /**
+ * An object representing an application. Allows the developer to create,
+ * execute, show/close an application as well as listen to {@link OpenFin.ApplicationEvents application events}.
+ */
+ class Application extends base_1.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire, identity) {
+ super(wire, 'application', identity.uuid);
+ this.identity = identity;
+ this.window = new window_1._Window(this.wire, {
+ uuid: this.identity.uuid,
+ name: this.identity.uuid
+ });
+ }
+ windowListFromIdentityList(identityList) {
+ const windowList = [];
+ identityList.forEach((identity) => {
+ windowList.push(new window_1._Window(this.wire, {
+ uuid: identity.uuid,
+ name: identity.name
+ }));
+ });
+ return windowList;
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function addListener
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function on
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function once
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependListener
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * The listener is added to the beginning of the listeners array.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependOnceListener
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Remove a listener from the listener array for the specified event.
+ * Caution: Calling this method changes the array indices in the listener array behind the listener.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function removeListener
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * Removes all listeners, or those of the specified event.
+ * @param eventType - The type of the event.
+ *
+ * @function removeAllListeners
+ * @memberof Application
+ * @instance
+ * @tutorial Application.EventEmitter
+ */
+ /**
+ * JumpListCategory interface
+ * @typedef { object } JumpListCategory
+ * @property { string } name The display title for the category. If omitted, items in this category will be placed into the standard 'Tasks' category. There can be only one such category, and it will always be displayed at the bottom of the JumpList.
+ * @property { JumpListItem[] } items Array of JumpListItem objects
+ */
+ /**
+ * @PORTED
+ * JumpListItem interface
+ * @typedef { object } JumpListItem
+ * @property { string } type One of the following: "task" or "separator". Defaults to task.
+ * @property { string } title The text to be displayed for the JumpList Item. Should only be set if type is "task".
+ * @property { string } description Description of the task (displayed in a tooltip). Should only be set if type is "task".
+ * @property { string } deepLink Deep link to a manifest, i.e: fins://path.to/manifest.json?$$param1=value1. See {@link https://developers.openfin.co/docs/deep-linking deep-linking} for more information.
+ * @property { string } iconPath The absolute path to an icon to be displayed for the item, which can be an arbitrary resource file that contains an icon (e.g. .ico, .exe, .dll).
+ * @property { number } iconIndex The index of the icon in the resource file. If a resource file contains multiple icons this value can be used to specify the zero-based index of the icon that should be displayed for this task. If a resource file contains only one icon, this property should be set to zero.
+ */
+ /**
+ * Determines if the application is currently running.
+ *
+ * @example
+ *
+ * ```js
+ * async function isAppRunning() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.isRunning();
+ * }
+ * isAppRunning().then(running => console.log(`Current app is running: ${running}`)).catch(err => console.log(err));
+ * ```
+ */
+ isRunning() {
+ return this.wire.sendAction('is-application-running', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Closes the application and any child windows created by the application.
+ * Cleans the application from state so it is no longer found in getAllApplications.
+ * @param force Close will be prevented from closing when force is false and
+ * ‘close-requested’ has been subscribed to for application’s main window.
+ *
+ * @example
+ *
+ * ```js
+ * async function closeApp() {
+ * const allApps1 = await fin.System.getAllApplications(); //[{uuid: 'app1', isRunning: true}, {uuid: 'app2', isRunning: true}]
+ * const app = await fin.Application.wrap({uuid: 'app2'});
+ * await app.quit();
+ * const allApps2 = await fin.System.getAllApplications(); //[{uuid: 'app1', isRunning: true}]
+ *
+ * }
+ * closeApp().then(() => console.log('Application quit')).catch(err => console.log(err));
+ * ```
+ */
+ async quit(force = false) {
+ try {
+ await this._close(force);
+ await this.wire.sendAction('destroy-application', { force, ...this.identity });
+ }
+ catch (error) {
+ const acceptableErrors = ['Remote connection has closed', 'Could not locate the requested application'];
+ if (!acceptableErrors.some((msg) => error.message.includes(msg))) {
+ throw error;
+ }
+ }
+ }
+ async _close(force = false) {
+ try {
+ await this.wire.sendAction('close-application', { force, ...this.identity });
+ }
+ catch (error) {
+ if (!error.message.includes('Remote connection has closed')) {
+ throw error;
+ }
+ }
+ }
+ /**
+ * @deprecated use Application.quit instead
+ * Closes the application and any child windows created by the application.
+ * @param force - Close will be prevented from closing when force is false and ‘close-requested’ has been subscribed to for application’s main window.
+ * @param callback - called if the method succeeds.
+ * @param errorCallback - called if the method fails. The reason for failure is passed as an argument.
+ *
+ * @example
+ *
+ * ```js
+ * async function closeApp() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.close();
+ * }
+ * closeApp().then(() => console.log('Application closed')).catch(err => console.log(err));
+ * ```
+ */
+ close(force = false) {
+ console.warn('Deprecation Warning: Application.close is deprecated Please use Application.quit');
+ this.wire.sendAction('application-close', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this._close(force);
+ }
+ /**
+ * Retrieves an array of wrapped fin.Windows for each of the application’s child windows.
+ *
+ * @example
+ *
+ * ```js
+ * async function getChildWindows() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.getChildWindows();
+ * }
+ *
+ * getChildWindows().then(children => console.log(children)).catch(err => console.log(err));
+ * ```
+ */
+ getChildWindows() {
+ return this.wire.sendAction('get-child-windows', this.identity).then(({ payload }) => {
+ const identityList = [];
+ payload.data.forEach((winName) => {
+ identityList.push({ uuid: this.identity.uuid, name: winName });
+ });
+ return this.windowListFromIdentityList(identityList);
+ });
+ }
+ /**
+ * Retrieves the JSON manifest that was used to create the application. Invokes the error callback
+ * if the application was not created from a manifest.
+ *
+ * @example
+ *
+ * ```js
+ * async function getManifest() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.getManifest();
+ * }
+ *
+ * getManifest().then(manifest => console.log(manifest)).catch(err => console.log(err));
+ * ```
+ */
+ getManifest() {
+ return this.wire.sendAction('get-application-manifest', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves UUID of the application that launches this application. Invokes the error callback
+ * if the application was created from a manifest.
+ *
+ * @example
+ *
+ * ```js
+ * async function getParentUuid() {
+ * const app = await fin.Application.start({
+ * uuid: 'app-1',
+ * name: 'myApp',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Application.getParentUuid.html',
+ * autoShow: true
+ * });
+ * return await app.getParentUuid();
+ * }
+ *
+ * getParentUuid().then(parentUuid => console.log(parentUuid)).catch(err => console.log(err));
+ * ```
+ */
+ getParentUuid() {
+ return this.wire.sendAction('get-parent-application', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves current application's shortcut configuration.
+ *
+ * @example
+ *
+ * ```js
+ * async function getShortcuts() {
+ * const app = await fin.Application.wrap({ uuid: 'testapp' });
+ * return await app.getShortcuts();
+ * }
+ * getShortcuts().then(config => console.log(config)).catch(err => console.log(err));
+ * ```
+ */
+ getShortcuts() {
+ return this.wire.sendAction('get-shortcuts', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves current application's views.
+ * @experimental
+ *
+ * @example
+ *
+ * ```js
+ * async function getViews() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.getViews();
+ * }
+ * getViews().then(views => console.log(views)).catch(err => console.log(err));
+ * ```
+ */
+ async getViews() {
+ const { payload } = await this.wire.sendAction('application-get-views', this.identity);
+ return payload.data.map((id) => new view_1.View(this.wire, id));
+ }
+ /**
+ * Returns the current zoom level of the application.
+ *
+ * @example
+ *
+ * ```js
+ * async function getZoomLevel() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.getZoomLevel();
+ * }
+ *
+ * getZoomLevel().then(zoomLevel => console.log(zoomLevel)).catch(err => console.log(err));
+ * ```
+ */
+ getZoomLevel() {
+ return this.wire.sendAction('get-application-zoom-level', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns an instance of the main Window of the application
+ *
+ * @example
+ *
+ * ```js
+ * async function getWindow() {
+ * const app = await fin.Application.start({
+ * uuid: 'app-1',
+ * name: 'myApp',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Application.getWindow.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * getWindow().then(win => {
+ * win.showAt(0, 400);
+ * win.flash();
+ * }).catch(err => console.log(err));
+ * ```
+ */
+ getWindow() {
+ this.wire.sendAction('application-get-window', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return Promise.resolve(this.window);
+ }
+ /**
+ * Manually registers a user with the licensing service. The only data sent by this call is userName and appName.
+ * @param userName - username to be passed to the RVM.
+ * @param appName - app name to be passed to the RVM.
+ *
+ * @example
+ *
+ * ```js
+ * async function registerUser() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.registerUser('user', 'myApp');
+ * }
+ *
+ * registerUser().then(() => console.log('Successfully registered the user')).catch(err => console.log(err));
+ * ```
+ */
+ registerUser(userName, appName) {
+ return this.wire.sendAction('register-user', { userName, appName, ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Removes the application’s icon from the tray.
+ *
+ * @example
+ *
+ * ```js
+ * async function removeTrayIcon() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.removeTrayIcon();
+ * }
+ *
+ * removeTrayIcon().then(() => console.log('Removed the tray icon.')).catch(err => console.log(err));
+ * ```
+ */
+ removeTrayIcon() {
+ return this.wire.sendAction('remove-tray-icon', this.identity).then(() => undefined);
+ }
+ /**
+ * Restarts the application.
+ *
+ * @example
+ *
+ * ```js
+ * async function restartApp() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.restart();
+ * }
+ * restartApp().then(() => console.log('Application restarted')).catch(err => console.log(err));
+ * ```
+ */
+ restart() {
+ return this.wire.sendAction('restart-application', this.identity).then(() => undefined);
+ }
+ /**
+ * DEPRECATED method to run the application.
+ * Needed when starting application via {@link Application.create}, but NOT needed when starting via {@link Application.start}.
+ *
+ * @example
+ *
+ * ```js
+ * async function run() {
+ * const app = await fin.Application.create({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Application.run.html',
+ * autoShow: true
+ * });
+ * await app.run();
+ * }
+ * run().then(() => console.log('Application is running')).catch(err => console.log(err));
+ * ```
+ *
+ * @ignore
+ */
+ run() {
+ console.warn('Deprecation Warning: Application.run is deprecated Please use fin.Application.start');
+ this.wire.sendAction('application-run', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this._run();
+ }
+ _run(opts = {}) {
+ return this.wire
+ .sendAction('run-application', {
+ manifestUrl: this._manifestUrl,
+ opts,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Instructs the RVM to schedule one restart of the application.
+ *
+ * @example
+ *
+ * ```js
+ * async function scheduleRestart() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.scheduleRestart();
+ * }
+ *
+ * scheduleRestart().then(() => console.log('Application is scheduled to restart')).catch(err => console.log(err));
+ * ```
+ */
+ scheduleRestart() {
+ return this.wire.sendAction('relaunch-on-close', this.identity).then(() => undefined);
+ }
+ /**
+ * Sends a message to the RVM to upload the application's logs. On success,
+ * an object containing logId is returned.
+ *
+ * @example
+ *
+ * ```js
+ * async function sendLog() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.sendApplicationLog();
+ * }
+ *
+ * sendLog().then(info => console.log(info.logId)).catch(err => console.log(err));
+ * ```
+ */
+ async sendApplicationLog() {
+ const { payload } = await this.wire.sendAction('send-application-log', this.identity);
+ return payload.data;
+ }
+ /**
+ * Sets or removes a custom JumpList for the application. Only applicable in Windows OS.
+ * If categories is null the previously set custom JumpList (if any) will be replaced by the standard JumpList for the app (managed by Windows).
+ *
+ * Note: If the "name" property is omitted it defaults to "tasks".
+ * @param jumpListCategories An array of JumpList Categories to populate. If null, remove any existing JumpList configuration and set to Windows default.
+ *
+ *
+ * @remarks If categories is null the previously set custom JumpList (if any) will be replaced by the standard JumpList for the app (managed by Windows).
+ *
+ * The bottommost item in the jumplist will always be an item pointing to the current app. Its name is taken from the manifest's
+ * **` shortcut.name `** and uses **` shortcut.company `** as a fallback. Clicking that item will launch the app from its current manifest.
+ *
+ * Note: If the "name" property is omitted it defaults to "tasks".
+ *
+ * Note: Window OS caches jumplists icons, therefore an icon change might only be visible after the cache is removed or the
+ * uuid or shortcut.name is changed.
+ *
+ * @example
+ *
+ * ```js
+ * const app = fin.Application.getCurrentSync();
+ * const appName = 'My App';
+ * const jumpListConfig = [ // array of JumpList categories
+ * {
+ * // has no name and no type so `type` is assumed to be "tasks"
+ * items: [ // array of JumpList items
+ * {
+ * type: 'task',
+ * title: `Launch ${appName}`,
+ * description: `Runs ${appName} with the default configuration`,
+ * deepLink: 'fins://path.to/app/manifest.json',
+ * iconPath: 'https://path.to/app/icon.ico',
+ * iconIndex: 0
+ * },
+ * { type: 'separator' },
+ * {
+ * type: 'task',
+ * title: `Restore ${appName}`,
+ * description: 'Restore to last configuration',
+ * deepLink: 'fins://path.to/app/manifest.json?$$use-last-configuration=true',
+ * iconPath: 'https://path.to/app/icon.ico',
+ * iconIndex: 0
+ * },
+ * ]
+ * },
+ * {
+ * name: 'Tools',
+ * items: [ // array of JumpList items
+ * {
+ * type: 'task',
+ * title: 'Tool A',
+ * description: 'Runs Tool A',
+ * deepLink: 'fins://path.to/tool-a/manifest.json',
+ * iconPath: 'https://path.to/tool-a/icon.ico',
+ * iconIndex: 0
+ * },
+ * {
+ * type: 'task',
+ * title: 'Tool B',
+ * description: 'Runs Tool B',
+ * deepLink: 'fins://path.to/tool-b/manifest.json',
+ * iconPath: 'https://path.to/tool-b/icon.ico',
+ * iconIndex: 0
+ * }]
+ * }
+ * ];
+ *
+ * app.setJumpList(jumpListConfig).then(() => console.log('JumpList applied')).catch(e => console.log(`JumpList failed to apply: ${e.toString()}`));
+ * ```
+ *
+ * To handle deeplink args:
+ * ```js
+ * function handleUseLastConfiguration() {
+ * // this handler is called when the app is being launched
+ * app.on('run-requested', event => {
+ * if(event.userAppConfigArgs['use-last-configuration']) {
+ * // your logic here
+ * }
+ * });
+ * // this handler is called when the app was already running when the launch was requested
+ * fin.desktop.main(function(args) {
+ * if(args && args['use-last-configuration']) {
+ * // your logic here
+ * }
+ * });
+ * }
+ * ```
+ */
+ async setJumpList(jumpListCategories) {
+ await this.wire.sendAction('set-jump-list', { config: jumpListCategories, ...this.identity });
+ }
+ /**
+ * Adds a customizable icon in the system tray. To listen for a click on the icon use the `tray-icon-clicked` event.
+ * @param icon Image URL or base64 encoded string to be used as the icon
+ *
+ * @example
+ *
+ * ```js
+ * const imageUrl = "http://cdn.openfin.co/assets/testing/icons/circled-digit-one.png";
+ * const base64EncodedImage = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX\
+ * ///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII";
+ * const dataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DH\
+ * xgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ *
+ * async function setTrayIcon(icon) {
+ * const app = await fin.Application.getCurrent();
+ * return await app.setTrayIcon(icon);
+ * }
+ *
+ * // use image url to set tray icon
+ * setTrayIcon(imageUrl).then(() => console.log('Setting tray icon')).catch(err => console.log(err));
+ *
+ * // use base64 encoded string to set tray icon
+ * setTrayIcon(base64EncodedImage).then(() => console.log('Setting tray icon')).catch(err => console.log(err));
+ *
+ * // use a dataURL to set tray icon
+ * setTrayIcon(dataURL).then(() => console.log('Setting tray icon')).catch(err => console.log(err));
+ * ```
+ */
+ setTrayIcon(icon) {
+ return this.wire
+ .sendAction('set-tray-icon', {
+ enabledIcon: icon,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Sets new application's shortcut configuration. Windows only.
+ * @param config New application's shortcut configuration.
+ *
+ * @remarks Application has to be launched with a manifest and has to have shortcut configuration (icon url, name, etc.) in its manifest
+ * to be able to change shortcut states.
+ *
+ * @example
+ *
+ * ```js
+ * async function setShortcuts(config) {
+ * const app = await fin.Application.getCurrent();
+ * return app.setShortcuts(config);
+ * }
+ *
+ * setShortcuts({
+ * desktop: true,
+ * startMenu: false,
+ * systemStartup: true
+ * }).then(() => console.log('Shortcuts are set.')).catch(err => console.log(err));
+ * ```
+ */
+ setShortcuts(config) {
+ return this.wire.sendAction('set-shortcuts', { data: config, ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Sets the query string in all shortcuts for this app. Requires RVM 5.5+.
+ * @param queryString The new query string for this app's shortcuts.
+ *
+ * @example
+ *
+ * ```js
+ * const newQueryArgs = 'arg=true&arg2=false';
+ * const app = await fin.Application.getCurrent();
+ * try {
+ * await app.setShortcutQueryParams(newQueryArgs);
+ * } catch(err) {
+ * console.error(err)
+ * }
+ * ```
+ */
+ async setShortcutQueryParams(queryString) {
+ await this.wire.sendAction('set-shortcut-query-args', { data: queryString, ...this.identity });
+ }
+ /**
+ * Sets the zoom level of the application. The original size is 0 and each increment above or below represents zooming 20%
+ * larger or smaller to default limits of 300% and 50% of original size, respectively.
+ * @param level The zoom level
+ *
+ * @example
+ *
+ * ```js
+ * async function setZoomLevel(number) {
+ * const app = await fin.Application.getCurrent();
+ * return await app.setZoomLevel(number);
+ * }
+ *
+ * setZoomLevel(5).then(() => console.log('Setting a zoom level')).catch(err => console.log(err));
+ * ```
+ */
+ setZoomLevel(level) {
+ return this.wire.sendAction('set-application-zoom-level', { level, ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Sets a username to correlate with App Log Management.
+ * @param username Username to correlate with App's Log.
+ *
+ * @example
+ *
+ * ```js
+ * async function setAppLogUser() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.setAppLogUsername('username');
+ * }
+ *
+ * setAppLogUser().then(() => console.log('Success')).catch(err => console.log(err));
+ *
+ * ```
+ */
+ async setAppLogUsername(username) {
+ await this.wire.sendAction('set-app-log-username', { data: username, ...this.identity });
+ }
+ /**
+ * Retrieves information about the system tray. If the system tray is not set, it will throw an error message.
+ * @remarks The only information currently returned is the position and dimensions.
+ *
+ * @example
+ *
+ * ```js
+ * async function getTrayIconInfo() {
+ * const app = await fin.Application.wrap({ uuid: 'testapp' });
+ * return await app.getTrayIconInfo();
+ * }
+ * getTrayIconInfo().then(info => console.log(info)).catch(err => console.log(err));
+ * ```
+ */
+ getTrayIconInfo() {
+ return this.wire.sendAction('get-tray-icon-info', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Checks if the application has an associated tray icon.
+ *
+ * @example
+ *
+ * ```js
+ * const app = await fin.Application.wrap({ uuid: 'testapp' });
+ * const hasTrayIcon = await app.hasTrayIcon();
+ * console.log(hasTrayIcon);
+ * ```
+ */
+ hasTrayIcon() {
+ return this.wire.sendAction('has-tray-icon', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Closes the application by terminating its process.
+ *
+ * @example
+ *
+ * ```js
+ * async function terminateApp() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.terminate();
+ * }
+ * terminateApp().then(() => console.log('Application terminated')).catch(err => console.log(err));
+ * ```
+ */
+ terminate() {
+ return this.wire.sendAction('terminate-application', this.identity).then(() => undefined);
+ }
+ /**
+ * Waits for a hanging application. This method can be called in response to an application
+ * "not-responding" to allow the application to continue and to generate another "not-responding"
+ * message after a certain period of time.
+ *
+ * @ignore
+ */
+ wait() {
+ return this.wire.sendAction('wait-for-hung-application', this.identity).then(() => undefined);
+ }
+ /**
+ * Retrieves information about the application.
+ *
+ * @remarks If the application was not launched from a manifest, the call will return the closest parent application `manifest`
+ * and `manifestUrl`. `initialOptions` shows the parameters used when launched programmatically, or the `startup_app` options
+ * if launched from manifest. The `parentUuid` will be the uuid of the immediate parent (if applicable).
+ *
+ * @example
+ *
+ * ```js
+ * async function getInfo() {
+ * const app = await fin.Application.getCurrent();
+ * return await app.getInfo();
+ * }
+ *
+ * getInfo().then(info => console.log(info)).catch(err => console.log(err));
+ * ```
+ */
+ getInfo() {
+ return this.wire.sendAction('get-info', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves all process information for entities (windows and views) associated with an application.
+ *
+ * @example
+ * ```js
+ * const app = await fin.Application.getCurrent();
+ * const processInfo = await app.getProcessInfo();
+ * ```
+ * @experimental
+ */
+ async getProcessInfo() {
+ const { payload: { data } } = await this.wire.sendAction('application-get-process-info', this.identity);
+ return data;
+ }
+ /**
+ * Sets file auto download location. It's only allowed in the same application.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * API security settings.
+ * @param downloadLocation file auto download location
+ *
+ * @throws if setting file auto download location on different applications.
+ * @example
+ *
+ * ```js
+ * const downloadLocation = 'C:\\dev\\temp';
+ * const app = await fin.Application.getCurrent();
+ * try {
+ * await app.setFileDownloadLocation(downloadLocation);
+ * console.log('File download location is set');
+ * } catch(err) {
+ * console.error(err)
+ * }
+ * ```
+ */
+ async setFileDownloadLocation(downloadLocation) {
+ const { name } = this.wire.me;
+ const entityIdentity = { uuid: this.identity.uuid, name };
+ await this.wire.sendAction('set-file-download-location', { ...entityIdentity, downloadLocation });
+ }
+ /**
+ * Gets file auto download location. It's only allowed in the same application. If file auto download location is not set, it will return the default location.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * API security settings.
+ *
+ * @throws if getting file auto download location on different applications.
+ * @example
+ *
+ * ```js
+ * const app = await fin.Application.getCurrent();
+ * const fileDownloadDir = await app.getFileDownloadLocation();
+ * ```
+ */
+ async getFileDownloadLocation() {
+ const { payload: { data } } = await this.wire.sendAction('get-file-download-location', this.identity);
+ return data;
+ }
+ }
+ Instance$6.Application = Application;
+ return Instance$6;
+}
+
+var hasRequiredFactory$2;
+
+function requireFactory$2 () {
+ if (hasRequiredFactory$2) return Factory$7;
+ hasRequiredFactory$2 = 1;
+ Object.defineProperty(Factory$7, "__esModule", { value: true });
+ Factory$7.ApplicationModule = void 0;
+ const base_1 = base;
+ const validate_1 = validate;
+ const Instance_1 = requireInstance$1();
+ /**
+ * Static namespace for OpenFin API methods that interact with the {@link Application} class, available under `fin.Application`.
+ */
+ class ApplicationModule extends base_1.Base {
+ /**
+ * Asynchronously returns an Application object that represents an existing application.
+ *
+ * @example
+ *
+ * ```js
+ * fin.Application.wrap({ uuid: 'testapp' })
+ * .then(app => app.isRunning())
+ * .then(running => console.log('Application is running: ' + running))
+ * .catch(err => console.log(err));
+ * ```
+ *
+ */
+ async wrap(identity) {
+ this.wire.sendAction('wrap-application').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1.Application(this.wire, identity);
+ }
+ /**
+ * Synchronously returns an Application object that represents an existing application.
+ *
+ * @example
+ *
+ * ```js
+ * const app = fin.Application.wrapSync({ uuid: 'testapp' });
+ * await app.close();
+ * ```
+ *
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('wrap-application-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1.Application(this.wire, identity);
+ }
+ async _create(appOptions) {
+ // set defaults:
+ if (appOptions.waitForPageLoad === undefined) {
+ appOptions.waitForPageLoad = false;
+ }
+ if (appOptions.autoShow === undefined && appOptions.isPlatformController === undefined) {
+ appOptions.autoShow = true;
+ }
+ await this.wire.sendAction('create-application', appOptions);
+ return this.wrap({ uuid: appOptions.uuid });
+ }
+ /**
+ * DEPRECATED method to create a new Application. Use {@link Application.ApplicationModule.start Application.start} instead.
+ *
+ * @example
+ *
+ * ```js
+ * async function createApp() {
+ * const app = await fin.Application.create({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Application.create.html',
+ * autoShow: true
+ * });
+ * await app.run();
+ * }
+ *
+ * createApp().then(() => console.log('Application is created')).catch(err => console.log(err));
+ * ```
+ *
+ * @ignore
+ */
+ create(appOptions) {
+ console.warn('Deprecation Warning: fin.Application.create is deprecated. Please use fin.Application.start');
+ this.wire.sendAction('application-create').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this._create(appOptions);
+ }
+ /**
+ * Creates and starts a new Application.
+ *
+ * @example
+ *
+ * ```js
+ * async function start() {
+ * return fin.Application.start({
+ * name: 'app-1',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Application.start.html',
+ * autoShow: true
+ * });
+ * }
+ * start().then(() => console.log('Application is running')).catch(err => console.log(err));
+ * ```
+ *
+ */
+ async start(appOptions) {
+ this.wire.sendAction('start-application').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const app = await this._create(appOptions);
+ await this.wire.sendAction('run-application', { uuid: appOptions.uuid });
+ return app;
+ }
+ /**
+ * Asynchronously starts a batch of applications given an array of application identifiers and manifestUrls.
+ * Returns once the RVM is finished attempting to launch the applications.
+ * @param opts - Parameters that the RVM will use.
+ *
+ * @example
+ *
+ * ```js
+ *
+ * const applicationInfoArray = [
+ * {
+ * "uuid": 'App-1',
+ * "manifestUrl": 'http://localhost:5555/app1.json',
+ * },
+ * {
+ * "uuid": 'App-2',
+ * "manifestUrl": 'http://localhost:5555/app2.json',
+ * },
+ * {
+ * "uuid": 'App-3',
+ * "manifestUrl": 'http://localhost:5555/app3.json',
+ * }
+ * ]
+ *
+ * fin.Application.startManyManifests(applicationInfoArray)
+ * .then(() => {
+ * console.log('RVM has finished launching the application list.');
+ * })
+ * .catch((err) => {
+ * console.log(err);
+ * })
+ * ```
+ *
+ * @experimental
+ */
+ async startManyManifests(applications, opts) {
+ return this.wire.sendAction('run-applications', { applications, opts }).then(() => undefined);
+ }
+ /**
+ * Asynchronously returns an Application object that represents the current application
+ *
+ * @example
+ *
+ * ```js
+ * async function isCurrentAppRunning () {
+ * const app = await fin.Application.getCurrent();
+ * return app.isRunning();
+ * }
+ *
+ * isCurrentAppRunning().then(running => {
+ * console.log(`Current app is running: ${running}`);
+ * }).catch(err => {
+ * console.error(err);
+ * });
+ *
+ * ```
+ */
+ getCurrent() {
+ this.wire.sendAction('get-current-application').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this.wrap({ uuid: this.wire.me.uuid });
+ }
+ /**
+ * Synchronously returns an Application object that represents the current application
+ *
+ * @example
+ *
+ * ```js
+ * async function isCurrentAppRunning () {
+ * const app = fin.Application.getCurrentSync();
+ * return app.isRunning();
+ * }
+ *
+ * isCurrentAppRunning().then(running => {
+ * console.log(`Current app is running: ${running}`);
+ * }).catch(err => {
+ * console.error(err);
+ * });
+ *
+ * ```
+ */
+ getCurrentSync() {
+ this.wire.sendAction('get-current-application-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this.wrapSync({ uuid: this.wire.me.uuid });
+ }
+ /**
+ * Retrieves application's manifest and returns a running instance of the application.
+ * @param manifestUrl - The URL of app's manifest.
+ * @param opts - Parameters that the RVM will use.
+ *
+ * @example
+ *
+ * ```js
+ * fin.Application.startFromManifest('http://localhost:5555/app.json').then(app => console.log('App is running')).catch(err => console.log(err));
+ *
+ * // For a local manifest file:
+ * fin.Application.startFromManifest('file:///C:/somefolder/app.json').then(app => console.log('App is running')).catch(err => console.log(err));
+ * ```
+ */
+ async startFromManifest(manifestUrl, opts) {
+ this.wire.sendAction('application-start-from-manifest').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const app = await this._createFromManifest(manifestUrl);
+ // @ts-expect-error using private method without warning.
+ await app._run(opts); // eslint-disable-line no-underscore-dangle
+ return app;
+ }
+ /**
+ * @deprecated Use {@link Application.ApplicationModule.startFromManifest Application.startFromManifest} instead.
+ * Retrieves application's manifest and returns a wrapped application.
+ * @param manifestUrl - The URL of app's manifest.
+ * @param callback - called if the method succeeds.
+ * @param errorCallback - called if the method fails. The reason for failure is passed as an argument.
+ *
+ * @example
+ *
+ * ```js
+ * fin.Application.createFromManifest('http://localhost:5555/app.json').then(app => console.log(app)).catch(err => console.log(err));
+ * ```
+ * @ignore
+ */
+ createFromManifest(manifestUrl) {
+ console.warn('Deprecation Warning: fin.Application.createFromManifest is deprecated. Please use fin.Application.startFromManifest');
+ this.wire.sendAction('application-create-from-manifest').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this._createFromManifest(manifestUrl);
+ }
+ _createFromManifest(manifestUrl) {
+ return this.wire
+ .sendAction('get-application-manifest', { manifestUrl })
+ .then(({ payload }) => {
+ const uuid = payload.data.platform ? payload.data.platform.uuid : payload.data.startup_app.uuid;
+ return this.wrap({ uuid });
+ })
+ .then((app) => {
+ app._manifestUrl = manifestUrl; // eslint-disable-line no-underscore-dangle
+ return app;
+ });
+ }
+ }
+ Factory$7.ApplicationModule = ApplicationModule;
+ return Factory$7;
+}
+
+var hasRequiredApplication;
+
+function requireApplication () {
+ if (hasRequiredApplication) return application;
+ hasRequiredApplication = 1;
+ (function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ /**
+ * Entry points for the OpenFin `Application` API (`fin.Application`).
+ *
+ * * {@link ApplicationModule} contains static members of the `Application` API, accessible through `fin.Application`.
+ * * {@link Application} describes an instance of an OpenFin Application, e.g. as returned by `fin.Application.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ */
+ __exportStar(requireFactory$2(), exports);
+ __exportStar(requireInstance$1(), exports);
+ } (application));
+ return application;
+}
+
+var hasRequiredInstance;
+
+function requireInstance () {
+ if (hasRequiredInstance) return Instance$7;
+ hasRequiredInstance = 1;
+ Object.defineProperty(Instance$7, "__esModule", { value: true });
+ Instance$7._Window = void 0;
+ /* eslint-disable import/prefer-default-export */
+ /* eslint-disable @typescript-eslint/no-unused-vars */
+ /* eslint-disable no-console */
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
+ const application_1 = requireApplication();
+ const main_1 = main;
+ const view_1 = requireView();
+ const warnings_1 = warnings;
+ /**
+ * @PORTED
+ * @typedef { object } Margins
+ * @property { string } [marginType]
+ * Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen,
+ * you will also need to specify `top`, `bottom`, `left`, and `right`.
+ *
+ * @property { number } [top] The top margin of the printed web page, in pixels.
+ * @property { number } [bottom] The bottom margin of the printed web page, in pixels.
+ * @property { number } [left] The left margin of the printed web page, in pixels.
+ * @property { number } [right] The right margin of the printed web page, in pixels.
+ */
+ /**
+ * @PORTED
+ * @typedef { object } Dpi
+ * @property { number } [horizontal] The horizontal dpi
+ * @property { number } [vertical] The vertical dpi
+ */
+ /**
+ * @PORTED
+ * @typedef { object } PrintOptions
+ * @property { boolean } [silent=false] Don't ask user for print settings.
+ * @property { boolean } [printBackground=false] Prints the background color and image of the web page.
+ * @property { string } [deviceName=''] Set the printer device name to use.
+ * @property { boolean } [color=true] Set whether the printed web page will be in color or grayscale.
+ * @property { Margins } [margins] Set margins for the printed web page
+ * @property { boolean } [landscape=false] Whether the web page should be printed in landscape mode.
+ * @property { number } [scaleFactor] The scale factor of the web page.
+ * @property { number } [pagesPerSheet] The number of pages to print per page sheet.
+ * @property { boolean } [collate] Whether the web page should be collated.
+ * @property { number } [copies] The number of copies of the web page to print.
+ * @property { Record } [pageRanges] The page range to print. Should have two keys: from and to.
+ * @property { string } [duplexMode] Set the duplex mode of the printed web page. Can be simplex, shortEdge, or longEdge.
+ * @property { Dpi } [dpi] Set dpi for the printed web page
+ */
+ /**
+ * @REMOVED
+ * PrinterInfo interface
+ * @typedef { object } PrinterInfo
+ * @property { string } name Printer Name
+ * @property { string } description Printer Description
+ * @property { number } status Printer Status
+ * @property { boolean } isDefault Indicates that system's default printer
+ */
+ /**
+ * @REMOVED
+ * SharedWorkerInfo interface
+ * @typedef { object } SharedWorkerInfo
+ * @property { string } id The unique id of the shared worker.
+ * @property { string } url The url of the shared worker.
+ */
+ /**
+ * @PORTED
+ * ContentCreationRule interface
+ * @typedef { object } ContentCreationRule
+ * @property { string } behavior 'view' | 'window' | 'browser' | 'block'
+ * @property { string[] } match List of [match patterns](https://developer.chrome.com/extensions/match_patterns).
+ * @property { object } options Window creation options or View creation options.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} Window~options
+ * @summary Window creation options.
+ * @desc This is the options object required by {@link Window.create Window.create}.
+ *
+ * Note that `name` is the only required property — albeit the `url` property is usually provided as well
+ * (defaults to `"about:blank"` when omitted).
+ *
+ * _This jsdoc typedef mirrors the `WindowOptions` TypeScript interface in `@types/openfin`._
+ *
+ * @property {object} [accelerator]
+ * Enable keyboard shortcuts for devtools, zoom, reload, and reload ignoring cache.
+ *
+ * @property {boolean} [accelerator.devtools=false]
+ * If `true`, enables the devtools keyboard shortcut:
+ * `Ctrl` + `Shift` + `I` _(Toggles Devtools)_
+ *
+ * @property {boolean} [accelerator.reload=false]
+ * If `true`, enables the reload keyboard shortcuts:
+ * `Ctrl` + `R` _(Windows)_
+ * `F5` _(Windows)_
+ * `Command` + `R` _(Mac)_
+ *
+ * @property {boolean} [accelerator.reloadIgnoringCache=false]
+ * If `true`, enables the reload-from-source keyboard shortcuts:
+ * `Ctrl` + `Shift` + `R` _(Windows)_
+ * `Shift` + `F5` _(Windows)_
+ * `Command` + `Shift` + `R` _(Mac)_
+ *
+ * @property {boolean} [accelerator.zoom=false]
+ * NOTE: It is not recommended to set this value to true for Windows in Platforms as that may lead to unexpected visual shifts in layout.
+ * If `true`, enables the zoom keyboard shortcuts:
+ * `Ctrl` + `+` _(Zoom In)_
+ * `Ctrl` + `Shift` + `+` _(Zoom In)_
+ * `Ctrl` + `NumPad+` _(Zoom In)_
+ * `Ctrl` + `-` _(Zoom Out)_
+ * `Ctrl` + `Shift` + `-` _(Zoom Out)_
+ * `Ctrl` + `NumPad-` _(Zoom Out)_
+ * `Ctrl` + `Scroll` _(Zoom In & Out)_
+ * `Ctrl` + `0` _(Restore to 100%)_
+ *
+ * @property {object} [alphaMask] - _Experimental._ _Updatable._
+ *
+ * alphaMask turns anything of matching RGB value transparent.
+ *
+ * Caveats:
+ * * Runtime flags --disable-gpu and --allow-unsafe-compositing are required. Note: Unclear behavior on remote Desktop support
+ * * User cannot click-through transparent regions
+ * * Not supported on Mac
+ * * Windows Aero must be enabled
+ * * Won't make visual sense on Pixel-pushed environments such as Citrix
+ * * Not supported on rounded corner windows
+ * @property {number} [alphaMask.red=-1] 0-255
+ * @property {number} [alphaMask.green=-1] 0-255
+ * @property {number} [alphaMask.blue=-1] 0-255
+ *
+ * @property {boolean} [alwaysOnTop=false] - _Updatable._
+ * A flag to always position the window at the top of the window stack.
+ *
+ * @property {object} [api]
+ * Configurations for API injection.
+ *
+ * @property {object} [api.iframe] Configure if the the API should be injected into iframes based on domain.
+ *
+ * @property {boolean} [api.iframe.crossOriginInjection=false] Controls if the `fin` API object is present for cross origin iframes.
+ * @property {boolean} [api.iframe.sameOriginInjection=true] Controls if the `fin` API object is present for same origin iframes.
+ *
+ * @property {string} [applicationIcon = ""] - _Deprecated_ - use `icon` instead.
+ *
+ * @property {number} [aspectRatio=0] - _Updatable._
+ * The aspect ratio of width to height to enforce for the window. If this value is equal to or less than zero,
+ * an aspect ratio will not be enforced.
+ *
+ * @property {string} [autoplayPolicy="no-user-gesture-required"]
+ * Autoplay policy to apply to content in the window, can be
+ * `no-user-gesture-required`, `user-gesture-required`,
+ * `document-user-activation-required`. Defaults to `no-user-gesture-required`.
+ *
+ * @property {boolean} [autoShow=true]
+ * A flag to automatically show the window when it is created.
+ *
+ * @property {string} [backgroundColor="#FFF"]
+ * The window’s _backfill_ color as a hexadecimal value. Not to be confused with the content background color
+ * (`document.body.style.backgroundColor`),
+ * this color briefly fills a window’s (a) content area before its content is loaded as well as (b) newly exposed
+ * areas when growing a window. Setting
+ * this value to the anticipated content background color can help improve user experience.
+ * Default is white.
+ *
+ * @property {object} [contentCreation]
+ * Apply rules that determine how user interaction (`window.open` and links) creates content.
+ * @property {ContentCreationRule[]} [contentCreation.rules = []] List of content creation rules.
+ *
+ * @property {object} [contentNavigation]
+ * Restrict navigation to URLs that match an allowed pattern.
+ * In the lack of an allowlist, navigation to URLs that match a denied pattern would be prohibited.
+ * See [here](https://developer.chrome.com/extensions/match_patterns) for more details.
+ * @property {string[]} [contentNavigation.allowlist=[]] List of allowed URLs.
+ * @property {string[]} [contentNavigation.denylist=[]] List of denied URLs.
+ *
+ * @property {object} [contentRedirect]
+ * Restrict redirects to URLs that match an allowed pattern.
+ * In the lack of an allowlist, redirects to URLs that match a denied pattern would be prohibited.
+ * See [here](https://developer.chrome.com/extensions/match_patterns) for more details.
+ * @property {string[]} [contentRedirect.allowlist=[]] List of allowed URLs.
+ * @property {string[]} [contentRedirect.denylist=[]] List of denied URLs.
+ *
+ * @property {boolean} [contextMenu=true] - _Updatable._
+ * A flag to show the context menu when right-clicking on a window.
+ * Gives access to the devtools for the window.
+ *
+ * @property {object} [contextMenuSettings] - _Updatable._
+ * Deprecated - superseded by {@link contextMenuOptions}, which offers a larger feature-set and cleaner syntax.
+ * Configure the context menu when right-clicking on a window.
+ * @property {boolean} [contextMenuSettings.enable=true] Should the context menu display on right click.
+ * @property {boolean} [contextMenuSettings.devtools=true] Should the context menu contain a button for opening devtools.
+ * @property {boolean} [contextMenuSettings.reload=true] Should the context menu contain a button for reloading the page.
+ *
+ * @property {object} [contextMenuOptions] - _Updatable._
+ * Configure the context menu when right-clicking on a window. Supported menu items:
+ * 'separator'
+ * 'cut'
+ * 'copy'
+ * 'paste'
+ * 'spellCheck'
+ * 'inspect'
+ * 'reload'
+ * 'navigateForward'
+ * 'navigateBack'
+ * 'print'
+ * @property {boolean} [contextMenuOptions.enabled = true] Should the context menu display on right click.
+ * @property {string[]} [contextMenuSettings.template=[]] List of context menu items to display on right-click.
+ *
+ * @property {object} [cornerRounding] - _Updatable._
+ * Defines and applies rounded corners for a frameless window. **NOTE:** On macOS corner is not ellipse but circle rounded by the
+ * average of _height_ and _width_.
+ * @property {number} [cornerRounding.height=0] The height in pixels.
+ * @property {number} [cornerRounding.width=0] The width in pixels.
+ *
+ * @property {any} [customContext=""] - _Updatable. Inheritable._
+ * A field that the user can use to attach serializable data that will be saved when {@link Platform#getSnapshot Platform.getSnapshot}
+ * is called. If a window in a Platform is trying to update or retrieve its own context, it can use the
+ * {@link Platform#setWindowContext Platform.setWindowContext} and {@link Platform#getWindowContext Platform.getWindowContext} calls.
+ * _When omitted, _inherits_ from the parent application._
+ * As opposed to customData, this is meant for frequent updates and sharing with other contexts. [Example]{@tutorial customContext}
+ *
+ * @property {any} [customData=""] - _Updatable. Inheritable._
+ * A field that the user can attach serializable data to be ferried around with the window options.
+ * _When omitted, _inherits_ from the parent application._
+ *
+ * @property {object[]} [customRequestHeaders]
+ * Defines list of custom headers for requests sent by the window.
+ * @property {string[]} [customRequestHeaders.urlPatterns=[]] The URL patterns for which the headers will be applied
+ * @property {object[]} [customRequestHeaders.headers=[]] Objects representing headers and their values,
+ * where the object key is the name of header and value at key is the value of the header
+ *
+ * @property {boolean} [closeOnLastViewRemoved=true] - _Experimental._ _Updatable._
+ * Toggling off would keep the Window alive even if all its Views were closed.
+ * This is meant for advanced users and should be used with caution.
+ * Limitations - Once a Layout has been emptied out of all views it's not usable anymore, and certain API calls will fail.
+ * Use `layout.replace` to create a fresh Layout instance in case you want to populate it with Views again.
+ * ** note ** - This option is ignored in non-Platforms apps.
+ *
+ * @property {boolean} [defaultCentered=false]
+ * Centers the window in the primary monitor. This option overrides `defaultLeft` and `defaultTop`. When `saveWindowState` is `true`,
+ * this value will be ignored for subsequent launches in favor of the cached value. **NOTE:** On macOS _defaultCenter_ is
+ * somewhat above center vertically.
+ *
+ * @property {number} [defaultHeight=500]
+ * The default height of the window. When `saveWindowState` is `true`, this value will be ignored for subsequent launches
+ * in favor of the cached value.
+ *
+ * @property {number} [defaultLeft=100]
+ * The default left position of the window. When `saveWindowState` is `true`, this value will be ignored for subsequent
+ * launches in favor of the cached value.
+ *
+ * @property {number} [defaultTop=100]
+ * The default top position of the window. When `saveWindowState` is `true`, this value will be ignored for subsequent
+ * launches in favor of the cached value.
+ *
+ * @property {number} [defaultWidth=800]
+ * The default width of the window. When `saveWindowState` is `true`, this value will be ignored for subsequent
+ * launches in favor of the cached value.
+ *
+ * @property {boolean} [includeInSnapshots=true] - _Updatable._
+ * When true, the window will be be included in snapshots returned by Platform.getSnapshot(). Turning this off may be desirable when dealing with
+ * inherently temporary windows whose state shouldn't be preserved, such as modals, menus, or popups.
+ *
+ * @property {boolean} [frame=true] - _Updatable._
+ * A flag to show the frame.
+ *
+ * @hidden-property {boolean} [hideOnClose=false] - A flag to allow a window to be hidden when the close button is clicked.
+ *
+ * @property {object[]} [hotkeys=[]] - _Updatable._
+ * Defines the list of hotkeys that will be emitted as a `hotkey` event on the window. For usage example see [example]{@tutorial hotkeys}.
+ * Within Platform, OpenFin also implements a set of pre-defined actions called
+ * [keyboard commands]{@link https://developers.openfin.co/docs/platform-api#section-5-3-using-keyboard-commands}
+ * that can be assigned to a specific hotkey in the platform manifest.
+ * @property {string} hotkeys.keys The key combination of the hotkey, i.e. "Ctrl+T"
+ * @property {boolean} [hotkeys.preventDefault=false] Whether or not to prevent default key handling before emitting the event
+ *
+ * @property {string} [icon] - _Updatable. Inheritable._
+ * A URL for the icon to be shown in the window title bar and the taskbar.
+ * When omitted, inherits from the parent application._
+ * note: Window OS caches taskbar icons, therefore an icon change might only be visible after the cache is removed or the uuid is changed.
+ *
+ * @property {number} [maxHeight=-1] - _Updatable._
+ * The maximum height of a window. Will default to the OS defined value if set to -1.
+ *
+ * @property {boolean} [maximizable=true] - _Updatable._
+ * A flag that lets the window be maximized.
+ *
+ * @property {number} [maxWidth=-1] - _Updatable._
+ * The maximum width of a window. Will default to the OS defined value if set to -1.
+ *
+ * @property {number} [minHeight=0] - _Updatable._
+ * The minimum height of a window.
+ *
+ * @property {boolean} [minimizable=true] - _Updatable._
+ * A flag that lets the window be minimized.
+ *
+ * @property {number} [minWidth=0] - _Updatable._
+ * The minimum width of a window.
+ *
+ * @property {Identity} [modalParentIdentity]
+ * Parent identity of a modal window. It will create a modal child window when this option is set.
+ *
+ * @property {string} name
+ * The name of the window.
+ *
+ * @property {number} [opacity=1.0] - _Updatable._
+ * A flag that specifies how transparent the window will be.
+ * Changing opacity doesn't work on Windows 7 without Aero so setting this value will have no effect there.
+ * This value is clamped between `0.0` and `1.0`.
+ * * In software composition mode, the runtime flag --allow-unsafe-compositing is required.
+ *
+ * @property {preloadScript[]} [preloadScripts] - _Inheritable_
+ * A list of scripts that are eval'ed before other scripts in the page. When omitted, _inherits_
+ * from the parent application.
+ *
+ * @property {string} [processAffinity]
+ * A string to attempt to group renderers together. Will only be used if pages are on the same origin.
+ *
+ * @property {boolean} [resizable=true] - _Updatable._
+ * A flag to allow the user to resize the window.
+ *
+ * @property {object} [resizeRegion] - _Updatable._
+ * Defines a region in pixels that will respond to user mouse interaction for resizing a frameless window.
+ * @property {number} [resizeRegion.bottomRightCorner=9]
+ * The size in pixels of an additional square resizable region located at the bottom right corner of a frameless window.
+ * @property {number} [resizeRegion.size=7]
+ * The size in pixels.
+ * @property {object} [resizeRegion.sides={top:true,right:true,bottom:true,left:true}]
+ * Sides that a window can be resized from.
+ *
+ * @property {boolean} [saveWindowState=true]
+ * A flag to cache the location of the window.
+ * ** note ** - This option is ignored in Platforms as it would cause inconsistent {@link Platform#applySnapshot applySnapshot} behavior.
+ *
+ * @property {boolean} [ignoreSavedWindowState]
+ * A flag to ignore previously cached state of the window. It defaults the opposite value of `saveWindowState` to maintain backwards compatibility.
+ *
+ * @property {boolean} [shadow=false]
+ * A flag to display a shadow on frameless windows.
+ * `shadow` and `cornerRounding` are mutually exclusive.
+ * On Windows 7, Aero theme is required.
+ *
+ * @property {boolean} [showBackgroundImages=false] - _Updatable._
+ * Platforms Only. If true, will show background images in the layout when the Views are hidden.
+ * This occurs when the window is resizing or a tab is being dragged within the layout.
+ *
+ * @property {boolean} [showTaskbarIcon=true] - _Updatable._ _Windows_.
+ * A flag to show the window's icon in the taskbar.
+ *
+ * @property {boolean} [smallWindow=false]
+ * A flag to specify a frameless window that can be be created and resized to less than 41x36 px (width x height).
+ * _Note: Caveats of small windows are no Aero Snap and drag to/from maximize._
+ * _Windows 10: Requires `maximizable` to be false. Resizing with the mouse is only possible down to 38x39 px._
+ *
+ * @property {boolean} [spellCheck=false]
+ * Enable spell check in input text fields for the window.
+ *
+ * @property {string} [state="normal"]
+ * The visible state of the window on creation.
+ * One of:
+ * * `"maximized"`
+ * * `"minimized"`
+ * * `"normal"`
+ *
+ * @property {string} [taskbarIcon=string] - Deprecated - use `icon` instead._Windows_.
+ *
+ * @property {string} [taskbarIconGroup=] - _Windows_.
+ * Specify a taskbar group for the window.
+ * _If omitted, defaults to app's uuid (`fin.Application.getCurrentSync().identity.uuid`)._
+ *
+ * @property {string} [url="about:blank"]
+ * The URL of the window.
+ *
+ * @property {string} [uuid=]
+ * The `uuid` of the application, unique within the set of all `Application`s running in OpenFin Runtime.
+ * If omitted, defaults to the `uuid` of the application spawning the window.
+ * If given, must match the `uuid` of the application spawning the window.
+ * In other words, the application's `uuid` is the only acceptable value, but is the default, so there's
+ * really no need to provide it.
+ *
+ * @property {boolean} [waitForPageLoad=false]
+ * When set to `true`, the window will not appear until the `window` object's `load` event fires.
+ * When set to `false`, the window will appear immediately without waiting for content to be loaded.
+ *
+ * @property {ViewVisibility} [viewVisibility]
+ * _Platform Windows Only_. Controls behavior for showing views when they are being resized by the user.
+ */
+ /**
+ * @PORTED
+ * @typedef {Object} ViewVisibility _Platform Windows Only_. Controls behavior for showing views when they are being resized by the user.
+ * @property {ShowViewsOnWindowResize} [showViewsOnWindowResize] Enables views to be shown when a Platform Window is being resized by the user.
+ * @property {ShowViewsOnSplitterDrag} [showViewsOnSplitterDrag] Allows views to be shown when they are resized by the user dragging the splitter between layout stacks.
+ * @property {ShowViewsOnTabDrag} [showViewsOnTabDrag] _Supported on Windows Operating Systems only_. Allows views to be shown when the user is dragging a tab around a layout.
+ */
+ /**
+ * @PORTED
+ * @typedef {Object} ShowViewsOnWindowResize _Platform Windows Only_. Enables views to be shown when a Platform Window is being resized by the user.
+ * @property {boolean} [enabled=false] Enables or disables showing Views when a Platform Window is being resized.
+ * @property {number} [paintIntervalMs=0] Number of miliseconds to wait between view repaints.
+ */
+ /**
+ * @REMOVED
+ * @typedef {Object} ShowViewsOnSplitterDrag _Platform Windows Only_. Allows views to be shown when they are resized by the user dragging the splitter between layout stacks.
+ * @property {boolean} [enabled=false] Enables or disables showing views when the layout splitter is being dragged.
+ */
+ /**
+ * @REMOVED
+ * @typedef {Object} ShowViewsOnTabDrag _Platform Windows Only_. Allows views to be shown when the user is manipulating the layout by repositioning a tab.
+ * @property {boolean} [enabled=false] Enables or disables showing views when a tab is being dragged.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} CapturePageOptions
+ * @property { Area } [area] The area of the window to be captured.
+ * @property { string } [format='png'] The format of the captured image. Can be 'png', 'jpg', or 'bmp'.
+ * @property { number } [quality=100] Number representing quality of JPEG image only. Between 0 - 100.
+ */
+ /**
+ * @PORTED
+ * @typedef { object } Area
+ * @property { number } height Area's height
+ * @property { number } width Area's width
+ * @property { number } x X coordinate of area's starting point
+ * @property { number } y Y coordinate of area's starting point
+ */
+ /**
+ * @PORTED
+ * @typedef {object} FindInPageOptions
+ * @property {boolean} [forward=true] Whether to search forward or backward.
+ * @property {boolean} [findNext=false] Whether to begin a new text finding session. Should be true for first requests, and false for subsequent requests. Defaults to false.
+ * @property {boolean} [matchCase=false] Whether search should be case-sensitive.
+ * @property {boolean} [wordStart=false] Whether to look only at the start of words.
+ * @property {boolean} [medialCapitalAsWordStart=false]
+ * When combined with wordStart, accepts a match in the middle of a word if the match begins with an uppercase letter followed by a
+ * lowercase or non-letter. Accepts several other intra-word matches.
+ */
+ /**
+ * @REMOVED
+ * @typedef {object} Transition
+ * @property {Opacity} opacity - The Opacity transition
+ * @property {Position} position - The Position transition
+ * @property {Size} size - The Size transition
+ */
+ /**
+ * @PORTED
+ * @typedef {object} TransitionOptions
+ * @property {boolean} interrupt - This option interrupts the current animation. When false it pushes
+ this animation onto the end of the animation queue.
+ * @property {boolean} relative - Treat 'opacity' as absolute or as a delta. Defaults to false.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} Size
+ * @property {number} duration - The total time in milliseconds this transition should take.
+ * @property {boolean} relative - Treat 'opacity' as absolute or as a delta. Defaults to false.
+ * @property {number} width - Optional if height is present. Defaults to the window's current width.
+ * @property {number} height - Optional if width is present. Defaults to the window's current height.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} Position
+ * @property {number} duration - The total time in milliseconds this transition should take.
+ * @property {boolean} relative - Treat 'opacity' as absolute or as a delta. Defaults to false.
+ * @property {number} left - Defaults to the window's current left position in virtual screen coordinates.
+ * @property {number} top - Defaults to the window's current top position in virtual screen coordinates.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} Opacity
+ * @property {number} duration - The total time in milliseconds this transition should take.
+ * @property {boolean} relative - Treat 'opacity' as absolute or as a delta. Defaults to false.
+ * @property {number} opacity - This value is clamped from 0.0 to 1.0.
+ */
+ /**
+ * @REMOVED
+ * Bounds is a interface that has the properties of height,
+ * width, left, top which are all numbers
+ * @typedef { object } Bounds
+ * @property { number } height Get the application height bound
+ * @property { number } width Get the application width bound
+ * @property { number } top Get the application top bound
+ * @property { number } left Get the application left bound
+ * @property { number } right Get the application right bound
+ * @property { number } bottom Get the application bottom bound
+ */
+ /**
+ * A basic window that wraps a native HTML window. Provides more fine-grained
+ * control over the window state such as the ability to minimize, maximize, restore, etc.
+ * By default a window does not show upon instantiation; instead the window's show() method
+ * must be invoked manually. The new window appears in the same process as the parent window.
+ * It has the ability to listen for {@link OpenFin.WindowEvents window specific events}.
+ */
+ // The window.Window name is taken
+ class _Window extends main_1.WebContents {
+ /**
+ * @internal
+ */
+ constructor(wire, identity) {
+ super(wire, identity, 'window');
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function addListener
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function on
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function once
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependListener
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * The listener is added to the beginning of the listeners array.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependOnceListener
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Remove a listener from the listener array for the specified event.
+ * Caution: Calling this method changes the array indices in the listener array behind the listener.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function removeListener
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * Removes all listeners, or those of the specified event.
+ * @param eventType - The type of the event.
+ *
+ * @function removeAllListeners
+ * @memberof Window
+ * @instance
+ * @tutorial Window.EventEmitter
+ */
+ /**
+ * create a new window
+ * @internal
+ */
+ createWindow(options) {
+ this.wire.sendAction('window-create-window', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return new Promise((resolve, reject) => {
+ const CONSTRUCTOR_CB_TOPIC = 'fire-constructor-callback';
+ // need to call pageResponse, otherwise when a child window is created, page is not loaded
+ const pageResponse = new Promise((resolve) => {
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ this.on(CONSTRUCTOR_CB_TOPIC, function fireConstructor(response) {
+ let cbPayload;
+ const { success } = response;
+ const responseData = response.data;
+ const { message } = responseData;
+ if (success) {
+ cbPayload = {
+ httpResponseCode: responseData.httpResponseCode,
+ apiInjected: responseData.apiInjected
+ };
+ }
+ else {
+ cbPayload = {
+ message: responseData.message,
+ networkErrorCode: responseData.networkErrorCode,
+ stack: responseData.stack
+ };
+ }
+ this.removeListener(CONSTRUCTOR_CB_TOPIC, fireConstructor);
+ resolve({
+ message,
+ cbPayload,
+ success
+ });
+ });
+ });
+ // set defaults:
+ if (options.waitForPageLoad === undefined) {
+ options.waitForPageLoad = false;
+ }
+ if (options.autoShow === undefined) {
+ options.autoShow = true;
+ }
+ (0, warnings_1.handleDeprecatedWarnings)(options);
+ const windowCreation = this.wire.environment.createChildContent({ entityType: 'window', options });
+ Promise.all([pageResponse, windowCreation])
+ .then((resolvedArr) => {
+ const pageResolve = resolvedArr[0];
+ if (pageResolve.success) {
+ resolve(this);
+ }
+ else {
+ reject(pageResolve);
+ }
+ try {
+ // this is to enforce a 5.0 contract that the child's main function
+ // will not fire before the parent's success callback on creation.
+ // if the child window is not accessible (CORS) this contract does
+ // not hold.
+ const webWindow = this.getWebWindow();
+ webWindow.fin.__internal_.openerSuccessCBCalled();
+ }
+ catch (e) {
+ // common for main windows, we do not want to expose this error. here just to have a debug target.
+ // console.error(e);
+ }
+ })
+ .catch(reject);
+ });
+ }
+ /**
+ * Retrieves an array of frame info objects representing the main frame and any
+ * iframes that are currently on the page.
+ *
+ * @example
+ * ```js
+ * async function getAllFrames() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getAllFrames.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getAllFrames();
+ * }
+ *
+ * getAllFrames().then(framesInfo => console.log(framesInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getAllFrames() {
+ return this.wire.sendAction('get-all-frames', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Gets the current bounds (top, bottom, right, left, width, height) of the window.
+ *
+ * @example
+ * ```js
+ * async function getBounds() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getBounds.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getBounds();
+ * }
+ *
+ * getBounds().then(bounds => console.log(bounds)).catch(err => console.log(err));
+ * ```
+ */
+ getBounds() {
+ return this.wire
+ .sendAction('get-window-bounds', this.identity)
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * Centers the window on its current screen.
+ *
+ * @remarks Does not have an effect on minimized or maximized windows.
+ *
+ * @example
+ * ```js
+ * async function centerWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.center.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.center();
+ * }
+ *
+ * centerWindow().then(() => console.log('Window centered')).catch(err => console.log(err));
+ * ```
+ *
+ */
+ center() {
+ return this.wire.sendAction('center-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Removes focus from the window.
+ *
+ * @example
+ * ```js
+ * async function blurWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.blur.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.blur();
+ * }
+ *
+ * blurWindow().then(() => console.log('Blured Window')).catch(err => console.log(err));
+ * ```
+ */
+ blur() {
+ return this.wire.sendAction('blur-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Brings the window to the front of the window stack.
+ *
+ * @example
+ * ```js
+ * async function BringWindowToFront() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.bringToFront.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.bringToFront();
+ * }
+ *
+ * BringWindowToFront().then(() => console.log('Window is in the front')).catch(err => console.log(err));
+ * ```
+ */
+ bringToFront() {
+ return this.wire.sendAction('bring-window-to-front', this.identity).then(() => undefined);
+ }
+ /**
+ * Performs the specified window transitions.
+ * @param transitions - Describes the animations to perform. See the tutorial.
+ * @param options - Options for the animation. See the tutorial.
+ *
+ * @example
+ * ```
+ * async function animateWindow() {
+ * const transitions = {
+ * opacity: {
+ * opacity: 0.7,
+ * duration: 500
+ * },
+ * position: {
+ * top: 100,
+ * left: 100,
+ * duration: 500,
+ * relative: true
+ * }
+ * };
+ * const options = {
+ * interrupt: true,
+ * tween: 'ease-in'
+ * };
+ *
+ * const win = await fin.Window.getCurrent();
+ * return win.animate(transitions, options);
+ * }
+ *
+ * animateWindow()
+ * .then(() => console.log('Animation done'))
+ * .catch(err => console.error(err));
+ * ```
+ */
+ animate(transitions, options) {
+ return this.wire
+ .sendAction('animate-window', {
+ transitions,
+ options,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Hides the window.
+ *
+ * @example
+ * ```js
+ * async function hideWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.hide.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.hide();
+ * }
+ *
+ * hideWindow().then(() => console.log('Window is hidden')).catch(err => console.log(err));
+ * ```
+ */
+ hide() {
+ return this.wire.sendAction('hide-window', this.identity).then(() => undefined);
+ }
+ /**
+ * closes the window application
+ * @param force Close will be prevented from closing when force is false and
+ * ‘close-requested’ has been subscribed to for application’s main window.
+ *
+ * @example
+ * ```js
+ * async function closeWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.close.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.close();
+ * }
+ *
+ * closeWindow().then(() => console.log('Window closed')).catch(err => console.log(err));
+ * ```
+ */
+ close(force = false) {
+ return this.wire.sendAction('close-window', { force, ...this.identity }).then(() => {
+ Object.setPrototypeOf(this, null);
+ return undefined;
+ });
+ }
+ focusedWebViewWasChanged() {
+ return this.wire.sendAction('focused-webview-changed', this.identity).then(() => undefined);
+ }
+ /**
+ * Returns the native OS level Id.
+ *
+ * @remarks In Windows, it will return the Windows [handle](https://docs.microsoft.com/en-us/windows/desktop/WinProg/windows-data-types#HWND).
+ *
+ * @example
+ * ```js
+ * async function getWindowNativeId() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getNativeId.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getNativeId();
+ * }
+ *
+ * getWindowNativeId().then(nativeId => console.log(nativeId)).catch(err => console.log(err));
+ * ```
+ */
+ getNativeId() {
+ return this.wire.sendAction('get-window-native-id', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves window's attached views.
+ * @experimental
+ *
+ * @example
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * win.getCurrentViews()
+ * .then(views => console.log(views))
+ * .catch(console.error);
+ * ```
+ */
+ async getCurrentViews() {
+ const { payload } = await this.wire.sendAction('window-get-views', this.identity);
+ return payload.data.map((id) => new view_1.View(this.wire, id));
+ }
+ /**
+ * @deprecated Use {@link Window._Window.disableUserMovement} instead.
+ */
+ disableFrame() {
+ console.warn('Function is deprecated; use disableUserMovement instead.');
+ return this.wire.sendAction('disable-window-frame', this.identity).then(() => undefined);
+ }
+ /**
+ * Prevents a user from changing a window's size/position when using the window's frame.
+ *
+ * @example
+ * ```js
+ * async function disableUserMovement() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.disableFrame.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.disableUserMovement();
+ * }
+ *
+ * disableUserMovement().then(() => console.log('Window is disabled')).catch(err => console.log(err));
+ * ```
+ */
+ disableUserMovement() {
+ return this.wire.sendAction('disable-window-frame', this.identity).then(() => undefined);
+ }
+ /**
+ * @deprecated Use {@link Window._Window.enableUserMovement} instead.
+ */
+ enableFrame() {
+ console.warn('Function is deprecated; use enableUserMovement instead.');
+ return this.wire.sendAction('enable-window-frame', this.identity).then(() => undefined);
+ }
+ /**
+ * Re-enables user changes to a window's size/position when using the window's frame.
+ *
+ * @example
+ * ```js
+ * async function enableUserMovement() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-3',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.enableFrame.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.enableUserMovement();
+ * }
+ *
+ * enableUserMovement().then(() => console.log('Window is enabled')).catch(err => console.log(err));
+ * ```
+ */
+ enableUserMovement() {
+ return this.wire.sendAction('enable-window-frame', this.identity).then(() => undefined);
+ }
+ /**
+ * Flashes the window’s frame and taskbar icon until stopFlashing is called or until a focus event is fired.
+ *
+ * @remarks On macOS flash only works on inactive windows.
+ * @example
+ * ```js
+ * async function windowFlash() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.flash.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.flash();
+ * }
+ *
+ * windowFlash().then(() => console.log('Window flashing')).catch(err => console.log(err));
+ * ```
+ */
+ flash() {
+ return this.wire.sendAction('flash-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Stops the taskbar icon from flashing.
+ *
+ * @example
+ * ```js
+ * async function stopWindowFlashing() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.stopFlashing.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.stopFlashing();
+ * }
+ *
+ * stopWindowFlashing().then(() => console.log('Application window flashing')).catch(err => console.log(err));
+ * ```
+ */
+ stopFlashing() {
+ return this.wire.sendAction('stop-flash-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Gets an information object for the window.
+ *
+ * @example
+ * ```js
+ * async function getInfo() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getInfo.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getInfo();
+ * }
+ *
+ * getInfo().then(info => console.log(info)).catch(err => console.log(err));
+ * ```
+ */
+ getInfo() {
+ return this.wire.sendAction('get-window-info', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves the window's Layout
+ *
+ * @example
+ * ```js
+ * //get the current window
+ * const window = await fin.Window.getCurrent();
+ *
+ * //get the layout for the window
+ * const layout = await window.getLayout();
+ * ```
+ * @experimental
+ */
+ async getLayout(layoutIdentity) {
+ this.wire.sendAction('window-get-layout', this.identity).catch((e) => {
+ // don't expose
+ });
+ const opts = await this.getOptions();
+ if (!opts.layout || !opts.layoutSnapshot) {
+ throw new Error('Window does not have a Layout');
+ }
+ return this.fin.Platform.Layout.wrap(layoutIdentity ?? this.identity);
+ }
+ /**
+ * Gets the current settings of the window.
+ *
+ * @example
+ * ```js
+ * async function getWindowOptions() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getOptions.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getOptions();
+ * }
+ *
+ * getWindowOptions().then(opts => console.log(opts)).catch(err => console.log(err));
+ * ```
+ */
+ getOptions() {
+ return this.wire.sendAction('get-window-options', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Gets the parent application.
+ *
+ * @example
+ * ```js
+ * async function getParentApplication() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getParentApplication.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getParentApplication();
+ * }
+ *
+ * getParentApplication().then(parentApplication => console.log(parentApplication)).catch(err => console.log(err));
+ * ```
+ */
+ getParentApplication() {
+ this.wire.sendAction('window-get-parent-application', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return Promise.resolve(new application_1.Application(this.wire, this.identity));
+ }
+ /**
+ * Gets the parent window.
+ *
+ * @example
+ * ```js
+ * async function getParentWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getParentWindow.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getParentWindow();
+ * }
+ *
+ * getParentWindow().then(parentWindow => console.log(parentWindow)).catch(err => console.log(err));
+ * ```
+ */
+ getParentWindow() {
+ this.wire.sendAction('window-get-parent-window', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return Promise.resolve(new application_1.Application(this.wire, this.identity)).then((app) => app.getWindow());
+ }
+ /**
+ * ***DEPRECATED - please use Window.capturePage.***
+ * Gets a base64 encoded PNG image of the window or just part a of it.
+ * @param area The area of the window to be captured.
+ * Omitting it will capture the whole visible window.
+ *
+ * @tutorial Window.capturePage
+ */
+ async getSnapshot(area) {
+ const req = { area, ...this.identity };
+ console.warn('Window.getSnapshot has been deprecated, please use Window.capturePage');
+ const res = await this.wire.sendAction('get-window-snapshot', req);
+ return res.payload.data;
+ }
+ /**
+ * Gets the current state ("minimized", "maximized", or "normal") of the window.
+ *
+ * @example
+ * ```js
+ * async function getWindowState() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.getState.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.getState();
+ * }
+ *
+ * getWindowState().then(winState => console.log(winState)).catch(err => console.log(err));
+ * ```
+ */
+ getState() {
+ return this.wire.sendAction('get-window-state', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Previously called getNativeWindow.
+ * Returns the [Window Object](https://developer.mozilla.org/en-US/docs/Web/API/Window)
+ * that represents the web context of the target window. This is the same object that
+ * you would get from calling [window.open()](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) in a standard web context.
+ * The target window needs to be in the same application as the requesting window
+ * as well as comply with [same-origin](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) policy requirements.
+ *
+ * @example
+ * Injecting content into an empty window:
+ *
+ * ```js
+ * (async ()=> {
+ * try {
+ * const winName = `child-window-${Date.now()}`;
+ * const win = await fin.Window.create({
+ * name: winName,
+ * url: 'about:blank'
+ * });
+ * win.getWebWindow().document.write('
Hello World
');
+ * } catch (err) {
+ * console.error(err);
+ * }
+ * })();
+ * ```
+ *
+ * Cloning DOM elements from the parent window (in this example we clone an `h3` element from the parent window):
+ * ```js
+ * (async ()=> {
+ * try {
+ * const currentWindow = await fin.Window.getCurrent();
+ * const parentWindow = await currentWindow.getParentWindow();
+ * const clonedH3 = parentWindow.getWebWindow().document.querySelector('h3').cloneNode(true);
+ * document.body.append(clonedH3);
+ *
+ * } catch (err) {
+ * console.error(err);
+ * }
+ * })();
+ * ```
+ *
+ * Rendering on a child window via a library (in this example we are using the [lit-html](https://lit-html.polymer-project.org/)
+ * template library to render content on a blank child window. You are not going to be able to copy paste this example without
+ * configuring the project correctly but this would demonstrate some templating options available):
+ * ```js
+ * (async ()=> {
+ * try {
+ * const win = await fin.Window.create({
+ * name: `child-window-${Date.now()}`,
+ * url: 'about:blank'
+ * });
+ * const template = html`
+ *
+ * Click here:
+ *
+ *
`;
+ * render(template, win.getWebWindow().document.body);
+ *
+ * } catch (err) {
+ * console.error(err);
+ * }
+ * })();
+ * ```
+ */
+ getWebWindow() {
+ this.wire.sendAction('window-get-web-window', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this.wire.environment.getWebWindow(this.identity);
+ }
+ /**
+ * Determines if the window is a main window.
+ *
+ * @example
+ * ```js
+ * const wnd = fin.Window.getCurrentSync();
+ * const isMainWnd = wnd.isMainWindow();
+ * console.log('Is this a main window? ' + isMainWnd);
+ * ```
+ */
+ isMainWindow() {
+ this.wire.sendAction('window-is-main-window', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return this.me.uuid === this.me.name;
+ }
+ /**
+ * Determines if the window is currently showing.
+ *
+ * @example
+ * ```js
+ * async function isWindowShowing() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.isShowing.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.isShowing();
+ * }
+ *
+ * isWindowShowing().then(bool => console.log(bool)).catch(err => console.log(err));
+ * ```
+ */
+ isShowing() {
+ return this.wire.sendAction('is-window-showing', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Maximizes the window
+ *
+ * @example
+ * ```js
+ * async function maxWindow() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.maximize.html',
+ * autoShow: true
+ * });
+ * const win = await app.getWindow();
+ * return await win.maximize();
+ * }
+ *
+ * maxWindow().then(() => console.log('Maximized window')).catch(err => console.log(err));
+ * ```
+ */
+ maximize() {
+ return this.wire.sendAction('maximize-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Minimizes the window.
+ *
+ * @example
+ * ```js
+ * async function minWindow() {
+ * const win = await fin.Window.getCurrent();
+ * return await win.minimize();
+ * }
+ *
+ * minWindow().then(() => console.log('Minimized window')).catch(err => console.log(err));
+ * ```
+ */
+ minimize() {
+ return this.wire.sendAction('minimize-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Moves the window by a specified amount.
+ * @param deltaLeft The change in the left position of the window
+ * @param deltaTop The change in the top position of the window
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.moveBy.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function moveBy(left, top) {
+ * const win = await createWin();
+ * return await win.moveBy(left, top);
+ * }
+ *
+ * moveBy(580, 300).then(() => console.log('Moved')).catch(err => console.log(err));
+ * ```
+ */
+ moveBy(deltaLeft, deltaTop, positioningOptions) {
+ return this.wire
+ .sendAction('move-window-by', {
+ deltaLeft,
+ deltaTop,
+ positioningOptions,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Moves the window to a specified location.
+ * @param left The left position of the window
+ * @param top The top position of the window
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.moveTo.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function moveTo(left, top) {
+ * const win = await createWin();
+ * return await win.moveTo(left, top)
+ * }
+ *
+ * moveTo(580, 300).then(() => console.log('Moved')).catch(err => console.log(err))
+ * ```
+ */
+ moveTo(left, top, positioningOptions) {
+ return this.wire
+ .sendAction('move-window', {
+ left,
+ top,
+ positioningOptions,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Resizes the window by a specified amount.
+ * @param deltaWidth The change in the width of the window
+ * @param deltaHeight The change in the height of the window
+ * @param anchor Specifies a corner to remain fixed during the resize.
+ * Can take the values: "top-left", "top-right", "bottom-left", or "bottom-right".
+ * If undefined, the default is "top-left"
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.resizeBy.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function resizeBy(left, top, anchor) {
+ * const win = await createWin();
+ * return await win.resizeBy(left, top, anchor)
+ * }
+ *
+ * resizeBy(580, 300, 'top-right').then(() => console.log('Resized')).catch(err => console.log(err));
+ * ```
+ */
+ resizeBy(deltaWidth, deltaHeight, anchor, positioningOptions) {
+ return this.wire
+ .sendAction('resize-window-by', {
+ deltaWidth: Math.floor(deltaWidth),
+ deltaHeight: Math.floor(deltaHeight),
+ anchor,
+ positioningOptions,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Resizes the window to the specified dimensions.
+ * @param width The change in the width of the window
+ * @param height The change in the height of the window
+ * @param anchor Specifies a corner to remain fixed during the resize.
+ * Can take the values: "top-left", "top-right", "bottom-left", or "bottom-right".
+ * If undefined, the default is "top-left"
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.resizeTo.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function resizeTo(left, top, anchor) {
+ * const win = await createWin();
+ * return await win.resizeTo(left, top, anchor);
+ * }
+ *
+ * resizeTo(580, 300, 'top-left').then(() => console.log('Resized')).catch(err => console.log(err));
+ * ```
+ */
+ resizeTo(width, height, anchor, positioningOptions) {
+ return this.wire
+ .sendAction('resize-window', {
+ width: Math.floor(width),
+ height: Math.floor(height),
+ anchor,
+ positioningOptions,
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Restores the window to its normal state (i.e., unminimized, unmaximized).
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.restore.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function restore() {
+ * const win = await createWin();
+ * return await win.restore();
+ * }
+ *
+ * restore().then(() => console.log('Restored')).catch(err => console.log(err));
+ * ```
+ */
+ restore() {
+ return this.wire.sendAction('restore-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Will bring the window to the front of the entire stack and give it focus.
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.setAsForeground.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function setAsForeground() {
+ * const win = await createWin();
+ * return await win.setAsForeground()
+ * }
+ *
+ * setAsForeground().then(() => console.log('In the foreground')).catch(err => console.log(err));
+ * ```
+ */
+ setAsForeground() {
+ return this.wire.sendAction('set-foreground-window', this.identity).then(() => undefined);
+ }
+ /**
+ * Sets the window's size and position.
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.setBounds.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function setBounds(bounds) {
+ * const win = await createWin();
+ * return await win.setBounds(bounds);
+ * }
+ *
+ * setBounds({
+ * height: 100,
+ * width: 200,
+ * top: 400,
+ * left: 400
+ * }).then(() => console.log('Bounds set to window')).catch(err => console.log(err));
+ * ```
+ */
+ setBounds(bounds, positioningOptions) {
+ return this.wire
+ .sendAction('set-window-bounds', { ...bounds, ...this.identity, positioningOptions })
+ .then(() => undefined);
+ }
+ /**
+ * Shows the window if it is hidden.
+ * @param force Show will be prevented from showing when force is false and
+ * ‘show-requested’ has been subscribed to for application’s main window.
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.show.html',
+ * autoShow: false
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function show() {
+ * const win = await createWin();
+ * return await win.show()
+ * }
+ *
+ * show().then(() => console.log('Showing')).catch(err => console.log(err));
+ * ```
+ */
+ show(force = false) {
+ return this.wire.sendAction('show-window', { force, ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Shows the window if it is hidden at the specified location.
+ *
+ * @param left The left position of the window in pixels
+ * @param top The top position of the window in pixels
+ * @param force Show will be prevented from closing when force is false and
+ * ‘show-requested’ has been subscribed to for application’s main window
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.showAt.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ *
+ * async function showAt(left, top) {
+ * const win = await createWin();
+ * return await win.showAt(left, top)
+ * }
+ *
+ * showAt(580, 300).then(() => console.log('Showing at')).catch(err => console.log(err));
+ * ```
+ */
+ showAt(left, top, force = false) {
+ return this.wire
+ .sendAction('show-at-window', {
+ force,
+ left: Math.floor(left),
+ top: Math.floor(top),
+ ...this.identity
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Shows the Chromium Developer Tools
+ *
+ * @tutorial Window.showDeveloperTools
+ */
+ /**
+ * Updates the window using the passed options.
+ *
+ * @remarks Values that are objects are deep-merged, overwriting only the values that are provided.
+ * @param options Changes a window's options that were defined upon creation. See tutorial
+ *
+ * @example
+ * ```js
+ * async function updateOptions() {
+ * const win = await fin.Window.getCurrent();
+ * return win.updateOptions({maxWidth: 100});
+ * }
+ * updateOptions().then(() => console.log('options is updated')).catch(err => console.error(err));
+ * ```
+ */
+ updateOptions(options) {
+ return this.wire.sendAction('update-window-options', { options, ...this.identity }).then(() => undefined);
+ }
+ /**
+ * Provides credentials to authentication requests
+ * @param userName userName to provide to the authentication challenge
+ * @param password password to provide to the authentication challenge
+ *
+ * @example
+ * ```js
+ * fin.Application.wrap({uuid: 'OpenfinPOC'}).then(app => {
+ * app.on('window-auth-requested', evt => {
+ * let win = fin.Window.wrap({ uuid: evt.uuid, name: evt.name});
+ * win.authenticate('userName', 'P@assw0rd').then(()=> console.log('authenticated')).catch(err => console.log(err));
+ * });
+ * });
+ * ```
+ */
+ authenticate(userName, password) {
+ return this.wire
+ .sendAction('window-authenticate', { userName, password, ...this.identity })
+ .then(() => undefined);
+ }
+ /**
+ * @typedef {object} ShowPopupMenuOptions
+ * @property {Array} template - An array describing the menu to show.
+ * @property {number} [x] - The window x coordinate where to show the menu. Defaults to mouse position. If using must also use `y`.
+ * @property {number} [y] - The window y coordinate where to show the menu. Defaults to mouse position. If using must also use `x`
+ */
+ /**
+ * @typedef {object} MenuItemTemplate
+ * @property {*} data - Data to be returned if the user selects the element. Must be serializable. Large objects can have a performance impact.
+ * @property {'normal' | 'separator' | 'submenu' | 'checkbox'} [type] - Defaults to 'normal' unless a 'submenu' key exists
+ * @property {string} [label] - The text to show on the menu item. Should be left undefined for `type: 'separator'`
+ * @property {boolean} [enabled] - If false, the menu item will be greyed out and unclickable.
+ * @property {boolean} [visible] - If false, the menu item will be entirely hidden.
+ * @property {boolean} [checked] - Should only be specified for `checkbox` type menu items.
+ * @property {string} [icon] - Image Data URI with image dimensions inferred from the encoded string
+ * @property {Array} [submenu] Should be specified for `submenu` type menu items. If `submenu` is specified, the `type: 'submenu'` can be omitted.
+ */
+ /**
+ * @typedef {object} MenuResult
+ * @property {'clicked' | 'closed'} result - Whether the user clicked on a menu item or the menu was closed (user clicked elsewhere).
+ * @property {* | undefined} [data] - The data property of the menu item clicked by the user. Only defined if result was `clicked`.
+ */
+ /**
+ * Shows a menu on the window.
+ *
+ * @remarks Returns a promise that resolves when the user has either selected an item or closed the menu. (This may take longer than other apis).
+ * Resolves to an object with `{result: 'clicked', data }` where data is the data field on the menu item clicked, or `{result 'closed'}` when the user doesn't select anything.
+ * Calling this method will close previously opened menus.
+ * @experimental
+ * @param options
+ * @typeParam Data User-defined shape for data returned upon menu item click. Should be a
+ * [union](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)
+ * of all possible data shapes for the entire menu, and the click handler should process
+ * these with a "reducer" pattern.
+ * @example
+ * This could be used to show a drop down menu over views in a platform window:
+ * ```js
+ * const template = [
+ * {
+ * label: 'Menu Item 1',
+ * data: 'hello from item 1'
+ * },
+ * { type: 'separator' },
+ * {
+ * label: 'Menu Item 2',
+ * type: 'checkbox',
+ * checked: true,
+ * data: 'The user clicked the checkbox'
+ * },
+ * {
+ * label: 'see more',
+ * enabled: false,
+ * submenu: [
+ * { label: 'submenu 1', data: 'hello from submenu' }
+ * ]
+ * }
+ * ]
+ * fin.me.showPopupMenu({ template }).then(r => {
+ * if (r.result === 'closed') {
+ * console.log('nothing happened');
+ * } else {
+ * console.log(r.data)
+ * }
+ * })
+ * ```
+ *
+ * Overriding the built in context menu (ote that this can be done per element or document wide):
+ * ```js
+ * document.addEventListener('contextmenu', e => {
+ * e.preventDefault();
+ * const template = [
+ * {
+ * label: 'Menu Item 1',
+ * data: 'hello from item 1'
+ * },
+ * { type: 'separator' },
+ * {
+ * label: 'Menu Item 2',
+ * type: 'checkbox',
+ * checked: true,
+ * data: 'The user clicked the checkbox'
+ * },
+ * {
+ * label: 'see more',
+ * enabled: false,
+ * submenu: [
+ * { label: 'submenu 1', data: 'hello from submenu' }
+ * ]
+ * }
+ * ]
+ * fin.me.showPopupMenu({ template, x: e.x, y: e.y }).then(r => {
+ * if (r.result === 'closed') {
+ * console.log('nothing happened');
+ * } else {
+ * console.log(r.data)
+ * }
+ * })
+ * })
+ * ```
+ */
+ async showPopupMenu(options) {
+ const { payload } = await this.wire.sendAction('show-popup-menu', { options, ...this.identity });
+ return payload.data;
+ }
+ /**
+ * Closes the window's popup menu, if one exists.
+ * @experimental
+ *
+ * @remarks Only one popup menu will ever be showing at a time. Calling `showPopupMenu` will automatically close
+ * any existing popup menu.
+ *
+ *
+ * @example
+ * This could be used to close a popup menu if the user's mouse leaves an element for example.
+ *
+ * ```js
+ * await fin.me.closePopupMenu();
+ * ```
+ */
+ async closePopupMenu() {
+ return this.wire.sendAction('close-popup-menu', { ...this.identity }).then(() => undefined);
+ }
+ /**
+ * @PORTED
+ * @typedef {object} PopupOptions
+ * @property {string} [name] - If a window with this `name` exists, it will be shown as a popup. Otherwise, a new window with this `name` will be created. If this `name` is undefined, `initialOptions.name` will be used. If this `name` and `intialOptions.name` are both undefined, a `name` will be generated.
+ * @property {string} [url] - Navigates to this `url` if showing an existing window as a popup, otherwise the newly created window will load this `url`.
+ * @property {Window~options} [initialOptions] - Window creation options when using `showPopupWindow` to create a new window.
+ * @property {Window~options} [additionalOptions] - Updatable window options applied to new and existing windows when shown as popups.
+ * @property {function} [onPopupResult] - Executed when this window's popup calls `dispatchPopupResult`. Note: if this is defined, `showPopupWindow` will not return a `PopupResult`.
+ * @property {function} [onPopupReady] - Executed when the popup window is shown. Provides the popup window to the provided function, and allows for easy access the popup window for additional behavior customization.
+ * @property {number} [height] - Height of the popup window (takes priority over `intialOptions` size properties).
+ * @property {number} [width] - Width of the popup window (takes priority over `intialOptions` size properties).
+ * @property {number} [x] - Left position where the popup window will be shown (relative to the window calling `showPopupWindow`).
+ * @property {number} [y] - Top position where the popup window will be shown (relative to the window calling `showPopupWindow`).
+ * @property {'modal' | 'hide' | 'close'} [blurBehavior] - Determines what happens if the popup window is blurred. 'modal' restricts resizing and positioning in the caller, 'hide' hides the popup window on blur and 'close' closes the popup window on blur.
+ * @property {'none' | 'hide' | 'close'} [resultDispatchBehavior] - Determines what happens when the popup window calls `dispatchPopupResult`. 'none' will do nothing, 'hide' hides the popup window on `dispatchPopupResult` and 'close' closes the popup window on `dispatchPopupResult`.
+ * @property {boolean} [focus] - Determines if the popup window should or should not be focused when it is shown.
+ * @property {boolean} [hideOnClose] - Hide the popup window instead of closing whenever `close` is called on it. Note: if this is `true` and `blurBehavior` and/or `resultDispatchBehavior` are set to `close`, the window will be hidden.
+ */
+ /**
+ * @PORTED
+ * @typedef {object} PopupResult
+ * @property {Identity} identity - `name` and `uuid` of the popup window that called dispatched this result.
+ * @property {'clicked' | 'dismissed'} result - Result of the user interaction with the popup window.
+ * @property {* | undefined} [data] - Data passed to `dispatchPopupResult`.
+ */
+ /**
+ * Dispatch a result to the caller of `showPopupWindow`.
+ *
+ * @remarks If this window isn't currently being shown as a popup, this call will silently fail.
+ * @param data Serializable data to send to the caller window.
+ *
+ * @example
+ * ```js
+ * await fin.me.dispatchPopupResult({
+ * foo: 'bar'
+ * });
+ * ```
+ */
+ async dispatchPopupResult(data) {
+ this.wire.sendAction('window-dispatch-popup-result', this.identity).catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ await this.wire.sendAction('dispatch-popup-result', { data, ...this.identity });
+ }
+ /**
+ * Prints the contents of the window.
+ *
+ * @param options Configuration for the print task.
+ * @remarks When `silent` is set to `true`, the API will pick the system's default printer if deviceName is empty
+ * and the default settings for printing.
+ *
+ * Use the CSS style `page-break-before: always;` to force print to a new page.
+ *
+ * @example
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * win.print({ silent: false, deviceName: 'system-printer-name' }).then(() => {
+ * console.log('print call has been sent to the system');
+ * });
+ * ```
+ *
+ * If a window has embedded views, those views will not print by default. To print a window's contents including embedded views,
+ * use the `content` option:
+ *
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ *
+ * // Print embedded views
+ * win.print({ content: 'views' });
+ *
+ * // Print screenshot of current window
+ * win.print({ content: 'screenshot' })
+ * ```
+ *
+ * When `content` is set to `views`, the embedded views in the platform window will be concatenated and printed as
+ * individual pages. If `includeSelf` is set to `true`, the platform window itself will be printed as the first
+ * page - be aware that this page will *not* include the embedded views - it will only include the contents of
+ * the platform window itself (e.g. tab stacks), with blank spaces where the view contents would be embedded.
+ *
+ * Due to a known issue, view contents that are not visible at the time `print` is called will not appear when
+ * printing `contents: views`. This includes views that are obscured behind other active UI elements.
+ *
+ * To print the views embedded in their page context, set `content` to `screenshot`.
+ */
+ async print(options = { content: 'self' }) {
+ switch (options.content) {
+ case undefined:
+ case 'self':
+ return super.print(options);
+ case 'screenshot':
+ return this.wire.sendAction('print-screenshot', this.identity).then(() => undefined);
+ case 'views':
+ return this.wire.sendAction('print-views', { ...this.identity, options }).then(() => undefined);
+ default:
+ return undefined;
+ }
+ }
+ }
+ Instance$7._Window = _Window;
+ return Instance$7;
+}
+
+var hasRequiredFactory$1;
+
+function requireFactory$1 () {
+ if (hasRequiredFactory$1) return Factory$8;
+ hasRequiredFactory$1 = 1;
+ Object.defineProperty(Factory$8, "__esModule", { value: true });
+ Factory$8._WindowModule = void 0;
+ const base_1 = base;
+ const validate_1 = validate;
+ const Instance_1 = requireInstance();
+ /**
+ * Static namespace for OpenFin API methods that interact with the {@link _Window} class, available under `fin.Window`.
+ */
+ class _WindowModule extends base_1.Base {
+ /**
+ * Asynchronously returns a Window object that represents an existing window.
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.wrap.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ * createWin().then(() => fin.Window.wrap({ uuid: 'app-1', name: 'myApp' }))
+ * .then(win => console.log('wrapped window'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ async wrap(identity) {
+ this.wire.sendAction('window-wrap').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1._Window(this.wire, identity);
+ }
+ /**
+ * Synchronously returns a Window object that represents an existing window.
+ *
+ * @example
+ * ```js
+ * async function createWin() {
+ * const app = await fin.Application.start({
+ * name: 'myApp',
+ * uuid: 'app-1',
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.wrapSync.html',
+ * autoShow: true
+ * });
+ * return await app.getWindow();
+ * }
+ * await createWin();
+ * let win = fin.Window.wrapSync({ uuid: 'app-1', name: 'myApp' });
+ * ```
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('window-wrap-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1._Window(this.wire, identity);
+ }
+ /**
+ * Creates a new Window.
+ * @param options - Window creation options
+ *
+ * @example
+ * ```js
+ * async function createWindow() {
+ * const winOption = {
+ * name:'child',
+ * defaultWidth: 300,
+ * defaultHeight: 300,
+ * url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.create.html',
+ * frame: true,
+ * autoShow: true
+ * };
+ * return await fin.Window.create(winOption);
+ * }
+ *
+ * createWindow().then(() => console.log('Window is created')).catch(err => console.log(err));
+ * ```
+ */
+ create(options) {
+ this.wire.sendAction('create-window').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const win = new Instance_1._Window(this.wire, { uuid: this.me.uuid, name: options.name });
+ return win.createWindow(options);
+ }
+ /**
+ * Asynchronously returns a Window object that represents the current window
+ *
+ * @example
+ * ```js
+ * fin.Window.getCurrent()
+ * .then(wnd => console.log('current window'))
+ * .catch(err => console.log(err));
+ *
+ * ```
+ */
+ getCurrent() {
+ this.wire.sendAction('get-current-window').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ if (!this.wire.me.isWindow) {
+ throw new Error('You are not in a Window context');
+ }
+ const { uuid, name } = this.wire.me;
+ return this.wrap({ uuid, name });
+ }
+ /**
+ * Synchronously returns a Window object that represents the current window
+ *
+ * @example
+ * ```js
+ * const wnd = fin.Window.getCurrentSync();
+ * const info = await wnd.getInfo();
+ * console.log(info);
+ *
+ * ```
+ */
+ getCurrentSync() {
+ this.wire.sendAction('get-current-window-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ if (!this.wire.me.isWindow) {
+ throw new Error('You are not in a Window context');
+ }
+ const { uuid, name } = this.wire.me;
+ return this.wrapSync({ uuid, name });
+ }
+ }
+ Factory$8._WindowModule = _WindowModule;
+ return Factory$8;
+}
+
+var hasRequiredWindow;
+
+function requireWindow () {
+ if (hasRequiredWindow) return window$1;
+ hasRequiredWindow = 1;
+ (function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ /**
+ * Entry points for the OpenFin `Window` API (`fin.Window`).
+ *
+ * * {@link _WindowModule} contains static members of the `Window` API, accessible through `fin.Window`.
+ * * {@link _Window} describes an instance of an OpenFin Window, e.g. as returned by `fin.Window.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * Underscore prefixing of OpenFin types that alias DOM entities will be fixed in a future version.
+ *
+ * @packageDocumentation
+ */
+ __exportStar(requireFactory$1(), exports);
+ __exportStar(requireInstance(), exports);
+ } (window$1));
+ return window$1;
+}
+
+/**
+ * Entry point for the OpenFin `System` API (`fin.System`).
+ *
+ * * {@link System} contains static members of the `System` API (available under `fin.System`)
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(system, "__esModule", { value: true });
+system.System = void 0;
+const base_1$j = base;
+const transport_errors_1$1 = transportErrors;
+const window_1 = requireWindow();
+const events_1$6 = require$$0;
+/**
+ * An object representing the core of OpenFin Runtime. Allows the developer
+ * to perform system-level actions, such as accessing logs, viewing processes,
+ * clearing the cache and exiting the runtime as well as listen to {@link OpenFin.SystemEvents system events}.
+ *
+ */
+class System extends base_1$j.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ super(wire, 'system');
+ }
+ sendExternalProcessRequest(action, options) {
+ return new Promise((resolve, reject) => {
+ const exitEventKey = 'external-process-exited';
+ let processUuid;
+ let exitPayload;
+ let externalProcessExitHandler;
+ let ofWindow;
+ if (typeof options.listener === 'function') {
+ externalProcessExitHandler = (payload) => {
+ const data = payload || {};
+ exitPayload = {
+ topic: 'exited',
+ uuid: data.processUuid || '',
+ exitCode: data.exitCode || 0
+ };
+ if (processUuid === payload.processUuid) {
+ options.listener(exitPayload);
+ ofWindow.removeListener(exitEventKey, externalProcessExitHandler);
+ }
+ };
+ // window constructor expects the name is not undefined
+ if (!this.wire.me.name) {
+ this.wire.me.name = this.wire.me.uuid;
+ }
+ ofWindow = new window_1._Window(this.wire, this.wire.me);
+ ofWindow.on(exitEventKey, externalProcessExitHandler);
+ }
+ this.wire
+ .sendAction(action, options)
+ .then(({ payload }) => {
+ processUuid = payload.data.uuid;
+ resolve(payload.data);
+ if (exitPayload && processUuid === exitPayload.uuid) {
+ options.listener(exitPayload);
+ ofWindow.removeListener(exitEventKey, externalProcessExitHandler);
+ }
+ })
+ .catch((err) => {
+ if (ofWindow) {
+ ofWindow.removeListener(exitEventKey, externalProcessExitHandler);
+ }
+ reject(err);
+ });
+ });
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function addListener
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function on
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function once
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependListener
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * The listener is added to the beginning of the listeners array.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependOnceListener
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Remove a listener from the listener array for the specified event.
+ * Caution: Calling this method changes the array indices in the listener array behind the listener.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function removeListener
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Removes all listeners, or those of the specified event.
+ * @param eventType - The type of the event.
+ *
+ * @function removeAllListeners
+ * @memberof System
+ * @instance
+ * @tutorial System.EventEmitter
+ */
+ /**
+ * Returns the version of the runtime. The version contains the major, minor,
+ * build and revision numbers.
+ *
+ * @example
+ * ```js
+ * fin.System.getVersion().then(v => console.log(v)).catch(err => console.log(err));
+ * ```
+ */
+ getVersion() {
+ return this.wire.sendAction('get-version').then(({ payload }) => payload.data);
+ }
+ /**
+ * Clears cached data containing application resource
+ * files (images, HTML, JavaScript files), cookies, and items stored in the
+ * Local Storage.
+ * @param options - See below for details.
+ *
+ * @remarks For more information on the accepted options, see the following pages:
+ * * cache: browsing data cache for html files and images ([caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching))
+ * * cookies: browser [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)
+ * * localStorage: browser data that can be used across sessions ([local storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage))
+ * * appcache: html5 [application cache](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache)
+ * @example
+ * ```js
+ * const clearCacheOptions = {
+ * appcache: true,
+ * cache: true,
+ * cookies: true,
+ * localStorage: true
+ * };
+ * fin.System.clearCache(clearCacheOptions).then(() => console.log('Cache cleared')).catch(err => console.log(err));
+ * ```
+ *
+ */
+ clearCache(options) {
+ return this.wire.sendAction('clear-cache', options).then(() => undefined);
+ }
+ /**
+ * Clears all cached data when OpenFin Runtime exits.
+ *
+ * @example
+ * ```js
+ * fin.System.deleteCacheOnExit().then(() => console.log('Deleted Cache')).catch(err => console.log(err));
+ * ```
+ */
+ deleteCacheOnExit() {
+ return this.wire.sendAction('delete-cache-request').then(() => undefined);
+ }
+ /**
+ * Exits the Runtime.
+ *
+ * @example
+ * ```js
+ * fin.System.exit().then(() => console.log('exit')).catch(err => console.log(err));
+ * ```
+ */
+ exit() {
+ return this.wire.sendAction('exit-desktop').then(() => undefined);
+ }
+ /**
+ * Fetches a JSON manifest using the browser process and returns a Javascript object.
+ * @param manifestUrl The URL of the manifest to fetch.
+ *
+ * @example
+ * ```js
+ * const manifest = await fin.System.fetchManifest('https://www.path-to-manifest.com');
+ * console.log(manifest);
+ * ```
+ */
+ async fetchManifest(manifestUrl) {
+ const { payload: { data } } = await this.wire.sendAction('fetch-manifest', { manifestUrl });
+ return data;
+ }
+ /**
+ * Writes any unwritten cookies data to disk.
+ *
+ * @example
+ * ```js
+ * fin.System.flushCookieStore()
+ * .then(() => console.log('success'))
+ * .catch(err => console.error(err));
+ * ```
+ */
+ flushCookieStore() {
+ return this.wire.sendAction('flush-cookie-store').then(() => undefined);
+ }
+ /**
+ * Retrieves an array of data (name, ids, bounds) for all application windows.
+ *
+ * @example
+ * ```js
+ * fin.System.getAllWindows().then(wins => console.log(wins)).catch(err => console.log(err));
+ * ```
+ */
+ getAllWindows() {
+ return this.wire.sendAction('get-all-windows').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an array of data for all applications.
+ *
+ * @example
+ * ```js
+ * fin.System.getAllApplications().then(apps => console.log(apps)).catch(err => console.log(err));
+ * ```
+ */
+ getAllApplications() {
+ return this.wire.sendAction('get-all-applications').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves the command line argument string that started OpenFin Runtime.
+ *
+ * @example
+ * ```js
+ * fin.System.getCommandLineArguments().then(args => console.log(args)).catch(err => console.log(err));
+ * ```
+ */
+ getCommandLineArguments() {
+ return this.wire.sendAction('get-command-line-arguments').then(({ payload }) => payload.data);
+ }
+ /**
+ * Get the current state of the crash reporter.
+ *
+ * @example
+ * ```js
+ * fin.System.getCrashReporterState().then(state => console.log(state)).catch(err => console.log(err));
+ * ```
+ */
+ async getCrashReporterState() {
+ const { payload: { data: { diagnosticMode, isRunning } } } = await this.wire.sendAction('get-crash-reporter-state');
+ console.warn('diagnosticMode property is deprecated. It will be removed in a future version');
+ return {
+ // diagnosticMode will be removed in a future version
+ diagnosticMode,
+ diagnosticsMode: diagnosticMode,
+ isRunning
+ };
+ }
+ /**
+ * Start the crash reporter if not already running.
+ * @param options - configure crash reporter
+ *
+ * @remarks You can optionally specify `diagnosticsMode` to have the logs sent to
+ * OpenFin on runtime close. (NOTE: `diagnosticsMode` will turn on verbose logging and disable the sandbox
+ * for newly launched renderer processes. See https://developers.openfin.co/of-docs/docs/debugging#diagnostics-mode for
+ * more details.)
+ *
+ * @example
+ * ```js
+ * fin.System.startCrashReporter({diagnosticsMode: true}).then(reporter => console.log(reporter)).catch(err => console.log(err));
+ * ```
+ */
+ async startCrashReporter(options) {
+ const opts = options;
+ const newOpts = { ...opts, diagnosticMode: opts.diagnosticsMode || opts.diagnosticMode };
+ const { payload: { data: { diagnosticMode, isRunning } } } = await this.wire.sendAction('start-crash-reporter', newOpts);
+ return {
+ // diagnosticMode will be removed in a future version
+ diagnosticMode,
+ diagnosticsMode: diagnosticMode,
+ isRunning
+ };
+ }
+ /**
+ * Returns a hex encoded hash of the machine id and the currently logged in user name.
+ * This is the recommended way to uniquely identify a user / machine combination.
+ *
+ * @remarks For Windows systems this is a sha256 hash of the machine ID set in the registry key:
+ * `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid` and `USERNAME`.
+ *
+ * For OSX systems, a native-level call is used to get the machine ID.
+ *
+ * @example
+ * ```js
+ * fin.System.getUniqueUserId().then(id => console.log(id)).catch(err => console.log(err));
+ * ```
+ */
+ getUniqueUserId() {
+ return this.wire.sendAction('get-unique-user-id').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves a frame info object for the uuid and name passed in
+ * @param uuid - The UUID of the target.
+ * @param name - The name of the target.
+ *
+ * @remarks The possible types are 'window', 'iframe', 'external connection' or 'unknown'.
+ * @example
+ * ```js
+ * const entityUuid = 'OpenfinPOC';
+ * const entityName = '40c74b5d-ed98-40f7-853f-e3d3c2699175';
+ * fin.System.getEntityInfo(entityUuid, entityName).then(info => console.log(info)).catch(err => console.log(err));
+ *
+ * // example info shape
+ * {
+ * "uuid": "OpenfinPOC",
+ * "name": "40c74b5d-ed98-40f7-853f-e3d3c2699175",
+ * "parent": {
+ * "uuid": "OpenfinPOC",
+ * "name": "OpenfinPOC"
+ * },
+ * "entityType": "iframe"
+ * }
+ * ```
+ */
+ getEntityInfo(uuid, name) {
+ return this.wire.sendAction('get-entity-info', { uuid, name }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Gets the value of a given environment variable on the computer on which the runtime is installed
+ *
+ * @example
+ * ```js
+ * fin.System.getEnvironmentVariable('HOME').then(env => console.log(env)).catch(err => console.log(err));
+ * ```
+ */
+ getEnvironmentVariable(envName) {
+ return this.wire
+ .sendAction('get-environment-variable', {
+ environmentVariables: envName
+ })
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * Get current focused window.
+ *
+ * @example
+ * ```js
+ * fin.System.getFocusedWindow().then(winInfo => console.log(winInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getFocusedWindow() {
+ return this.wire.sendAction('get-focused-window').then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns information about the given app's certification status
+ *
+ * @example
+ * ```js
+ * const manifestUrl = "http://localhost:1234/app.json"
+ * try {
+ * const certificationInfo = await fin.System.isAppCertified(manifestUrl);
+ * } catch(err) {
+ * console.error(err)
+ * }
+ * ```
+ */
+ async isAppCertified(manifestUrl) {
+ const { payload: { data: { certifiedInfo } } } = await this.wire.sendAction('is-app-certified', { manifestUrl });
+ return certifiedInfo;
+ }
+ /**
+ * Returns an array of all the installed runtime versions in an object.
+ *
+ * @example
+ * ```js
+ * fin.System.getInstalledRuntimes().then(runtimes => console.log(runtimes)).catch(err => console.log(err));
+ * ```
+ */
+ // incompatible with standalone node process.
+ getInstalledRuntimes() {
+ return this.wire.sendAction('get-installed-runtimes').then(({ payload }) => payload.data.runtimes);
+ }
+ // incompatible with standalone node process.
+ async getInstalledApps() {
+ const { payload: { data: { installedApps } } } = await this.wire.sendAction('get-installed-apps');
+ return installedApps;
+ }
+ /**
+ * Retrieves the contents of the log with the specified filename.
+ * @param options A object that id defined by the GetLogRequestType interface
+ *
+ * @example
+ * ```js
+ * async function getLog() {
+ * const logs = await fin.System.getLogList();
+ * return await fin.System.getLog(logs[0]);
+ * }
+ *
+ * getLog().then(log => console.log(log)).catch(err => console.log(err));
+ * ```
+ */
+ getLog(options) {
+ return this.wire.sendAction('view-log', options).then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns a unique identifier (UUID) provided by the machine.
+ *
+ * @example
+ * ```js
+ * fin.System.getMachineId().then(id => console.log(id)).catch(err => console.log(err));
+ * ```
+ */
+ getMachineId() {
+ return this.wire.sendAction('get-machine-id').then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns the minimum (inclusive) logging level that is currently being written to the log.
+ *
+ * @example
+ * ```js
+ * fin.System.getMinLogLevel().then(level => console.log(level)).catch(err => console.log(err));
+ * ```
+ */
+ getMinLogLevel() {
+ return this.wire.sendAction('get-min-log-level').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an array containing information for each log file.
+ *
+ * @example
+ * ```js
+ * fin.System.getLogList().then(logList => console.log(logList)).catch(err => console.log(err));
+ * ```
+ */
+ getLogList() {
+ return this.wire.sendAction('list-logs').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an object that contains data about the monitor setup of the
+ * computer that the runtime is running on.
+ *
+ * @example
+ * ```js
+ * fin.System.getMonitorInfo().then(monitorInfo => console.log(monitorInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getMonitorInfo() {
+ return this.wire.sendAction('get-monitor-info').then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns the mouse in virtual screen coordinates (left, top).
+ *
+ * @example
+ * ```js
+ * fin.System.getMousePosition().then(mousePosition => console.log(mousePosition)).catch(err => console.log(err));
+ * ```
+ */
+ getMousePosition() {
+ return this.wire.sendAction('get-mouse-position').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an array of all of the runtime processes that are currently
+ * running. Each element in the array is an object containing the uuid
+ * and the name of the application to which the process belongs.
+ * @deprecated Please use our new set of process APIs:
+ * {@link Window._Window#getProcessInfo Window.getProcessInfo}
+ * {@link View.View#getProcessInfo View.getProcessInfo}
+ * {@link Application.Application#getProcessInfo Application.getProcessInfo}
+ * {@link System#getAllProcessInfo System.getAllProcessInfo}
+ *
+ * @example
+ * ```js
+ * fin.System.getProcessList().then(ProcessList => console.log(ProcessList)).catch(err => console.log(err));
+ * ```
+ */
+ getProcessList() {
+ // eslint-disable-next-line no-console
+ console.warn('System.getProcessList has been deprecated. Please consider using our new process APIs: Window.getProcessInfo, View.getProcessInfo, Application.getProcessInfo, System.getAllProcessInfo');
+ return this.wire.sendAction('process-snapshot').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves all process information.
+ *
+ * @remarks This includes the browser process and every process associated to all entities (windows and views).
+ *
+ * @example
+ * ```js
+ * const allProcessInfo = await fin.System.getAllProcessInfo();
+ * ```
+ * @experimental
+ */
+ async getAllProcessInfo() {
+ const { payload: { data } } = await this.wire.sendAction('get-all-process-info', this.identity);
+ return data;
+ }
+ /**
+ * Retrieves the Proxy settings.
+ *
+ * @example
+ * ```js
+ * fin.System.getProxySettings().then(ProxySetting => console.log(ProxySetting)).catch(err => console.log(err));
+ *
+ * //This response has the following shape:
+ * {
+ * config: {
+ * proxyAddress: "proxyAddress", //the configured Proxy Address
+ * proxyPort: 0, //the configured Proxy port
+ * type: "system" //Proxy Type
+ * },
+ * system: {
+ * autoConfigUrl: "",
+ * bypass: "",
+ * enabled: false,
+ * proxy: ""
+ * }
+ * }
+ * ```
+ */
+ getProxySettings() {
+ return this.wire.sendAction('get-proxy-settings').then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns information about the running Runtime in an object.
+ *
+ * @example
+ * ```js
+ * fin.System.getRuntimeInfo().then(RuntimeInfo => console.log(RuntimeInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getRuntimeInfo() {
+ return this.wire.sendAction('get-runtime-info').then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns information about the running RVM in an object.
+ *
+ * @example
+ * ```js
+ * fin.System.getRvmInfo().then(RvmInfo => console.log(RvmInfo)).catch(err => console.log(err));
+ * ```
+ */
+ // incompatible with standalone node process.
+ getRvmInfo() {
+ return this.wire.sendAction('get-rvm-info').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves system information.
+ *
+ * @example
+ * ```js
+ * fin.System.getHostSpecs().then(specs => console.log(specs)).catch(err => console.log(err));
+ * ```
+ */
+ getHostSpecs() {
+ return this.wire.sendAction('get-host-specs').then(({ payload }) => payload.data);
+ }
+ /**
+ * Runs an executable or batch file. A path to the file must be included in options.
+ * A uuid may be optionally provided. If not provided, OpenFin will create a uuid for the new process.
+ * Note: This method is restricted by default and must be enabled via
+ * API security settings. Also, this api has an enhanced permission set to make it less dangerous. So application owners can only allow to launch the assets owned by the application, the enabled downloaded files or the restricted executables.
+ * @param options A object that is defined in the ExternalProcessRequestType interface
+ *
+ * @remarks If an unused UUID is provided in options, it will be used. If no UUID is provided, OpenFin will assign one.
+ * This api has an enhanced permission set to make it less dangerous. So application owners can only allow to launch the
+ * assets owned by the application, the enabled downloaded files or the restricted executables.
+ *
+ * **Note:** Since _appAssets_ relies on the RVM, which is missing on MAC_OS, 'alias' is not available. Instead provide
+ * the full path e.g. _/Applications/Calculator.app/Contents/MacOS/Calculator_.
+ *
+ * @example
+ * Basic Example:
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: 'notepad',
+ * arguments: '',
+ * listener: function (result) {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * Promise resolution:
+ *
+ * ```js
+ * //This response has the following shape:
+ * {
+ * uuid: "FB3E6E36-0976-4C2B-9A09-FB2E54D2F1BB" // The mapped UUID which identifies the launched process
+ * }
+ * ```
+ *
+ * Listener callback:
+ * ```js
+ * //This response has the following shape:
+ * {
+ * topic: "exited", // Or "released" on a call to releaseExternalProcess
+ * uuid: "FB3E6E36-0976-4C2B-9A09-FB2E54D2F1BB", // The mapped UUID which identifies the launched process
+ * exitCode: 0 // Process exit code
+ * }
+ * ```
+ *
+ * By specifying a lifetime, an external process can live as long the window/application that launched it or
+ * persist after the application exits. The default value is null, which is equivalent to 'persist', meaning
+ * the process lives on after the application exits:
+ *
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: 'notepad',
+ * arguments: '',
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * },
+ * lifetime: 'window'
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * Note: A process that exits when the window/application exits cannot be released via fin.desktop.System.releaseExternalProcess.
+ *
+ * By specifying a cwd, it will set current working directory when launching an external process:
+ *
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: 'cmd.exe',
+ * cwd: 'c:\\temp',
+ * arguments: '',
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * Example using an alias from app.json appAssets property:
+ *
+ * ```json
+ * "appAssets": [
+ * {
+ * "src": "exe.zip",
+ * "alias": "myApp",
+ * "version": "4.12.8",
+ * "target": "myApp.exe",
+ * "args": "a b c d"
+ * },
+ * ]
+ * ```
+ *
+ * ```js
+ * // When called, if no arguments are passed then the arguments (if any)
+ * // are taken from the 'app.json' file, from the 'args' parameter
+ * // of the 'appAssets' Object with the relevant 'alias'.
+ * fin.System.launchExternalProcess({
+ * //Additionally note that the executable found in the zip file specified in appAssets
+ * //will default to the one mentioned by appAssets.target
+ * //If the the path below refers to a specific path it will override this default
+ * alias: 'myApp',
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * Example using an alias but overriding the arguments:
+ *
+ * ```json
+ * "appAssets": [
+ * {
+ * "src": "exe.zip",
+ * "alias": "myApp",
+ * "version": "4.12.8",
+ * "target": "myApp.exe",
+ * "args": "a b c d"
+ * },
+ * ]
+ * ```
+ *
+ * ```js
+ * // If 'arguments' is passed as a parameter it takes precedence
+ * // over any 'args' set in the 'app.json'.
+ * fin.System.launchExternalProcess({
+ * alias: 'myApp',
+ * arguments: 'e f g',
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * It is now possible to optionally perform any combination of the following certificate checks
+ * against an absolute target via `fin.desktop.System.launchExternalProcess()`:
+ *
+ * ```js
+ * "certificate": {
+ * "serial": "3c a5 ...", // A hex string with or without spaces
+ * "subject": "O=OpenFin INC., L=New York, ...", // An internally tokenized and comma delimited string allowing partial or full checks of the subject fields
+ * "publickey": "3c a5 ...", // A hex string with or without spaces
+ * "thumbprint": "3c a5 ...", // A hex string with or without spaces
+ * "trusted": true // A boolean indicating that the certificate is trusted and not revoked
+ * }
+ * ```
+ *
+ * Providing this information as part of the default configurations for assets in an application's manifest
+ * will be added in a future RVM update:
+ *
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: 'C:\\Users\\ExampleUser\\AppData\\Local\\OpenFin\\OpenFinRVM.exe',
+ * arguments: '--version',
+ * certificate: {
+ * trusted: true,
+ * subject: 'O=OpenFin INC., L=New York, S=NY, C=US',
+ * thumbprint: '3c a5 28 19 83 05 fe 69 88 e6 8f 4b 3a af c5 c5 1b 07 80 5b'
+ * },
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * ```
+ *
+ * It is possible to launch files that have been downloaded by the user by listening to the window
+ * `file-download-completed` event and using the `fileUuid` provided by the event:
+ *
+ * ```js
+ * const win = fin.Window.getCurrentSync();
+ * win.addListener('file-download-completed', (evt) => {
+ * if (evt.state === 'completed') {
+ * fin.System.launchExternalProcess({
+ * fileUuid: evt.fileUuid,
+ * arguments: '',
+ * listener: (result) => {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => {
+ * console.log(processIdentity);
+ * }).catch(error => {
+ * console.log(error);
+ * });
+ * }
+ * });
+ * ```
+ *
+ * Launching assets specified in the app manifest:
+ *
+ * Sample appAssets section in app.json
+ * ```js
+ * "appAssets": [
+ * {
+ * "src": "http://filesamples.com/exe.zip",
+ * "alias": "myApp",
+ * "version": "4.12.8",
+ * "target": "myApp.exe",
+ * "args": "a b c d"
+ * },
+ * {
+ * "src": "http://examples.com/exe.zip",
+ * "alias": "myApp2",
+ * "version": "5.12.8",
+ * "target": "myApp2.exe",
+ * "args": "a b c"
+ * }
+ * ]
+ * ```
+ *
+ * This permission allows for launching of all assets specified in the above appAssets section. ("myApp" and "myApp2"):
+ *
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "launchExternalProcess": {
+ * "enabled": true,
+ * "assets": {
+ * "enabled": true
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * This permission allows for launching of _only_ the "myApp" asset in the above appAssets section, as defined in `srcRules`:
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "launchExternalProcess": {
+ * "enabled": true,
+ * "assets": {
+ * "enabled": true
+ * "srcRules": [
+ * {
+ * "match": [
+ * "*://filesamples.com/*"
+ * ],
+ * "behavior": "allow"
+ * },
+ * {
+ * "match": [
+ * ""
+ * ],
+ * "behavior": "block"
+ * }
+ * ]
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * Launching downloaded files:
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "launchExternalProcess": {
+ * "enabled": true,
+ * "downloads": {
+ * "enabled": true
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * This permission allows to launch all the executables:
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "launchExternalProcess": {
+ * "enabled": true,
+ * "executables": {
+ * "enabled": true
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ *
+ * This permission only allows launching of executables whose file paths match the corresponding `pathRules`:
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "launchExternalProcess": {
+ * "enabled": true,
+ * "executables": {
+ * "enabled": true
+ * "pathRules": [
+ * {
+ * "match": [
+ * "/Windows/System32/*.exe"
+ * ],
+ * "behavior": "allow"
+ * },
+ * {
+ * "match": [
+ * "*.exe"
+ * ],
+ * "behavior": "block"
+ * }
+ * ]
+ * }
+ * }
+ * }
+ * }
+ * ```
+ */
+ launchExternalProcess(options) {
+ return this.sendExternalProcessRequest('launch-external-process', options);
+ }
+ /**
+ * Monitors a running process. A pid for the process must be included in options.
+ * A uuid may be optionally provided. If not provided, OpenFin will create a uuid for the new process.
+ *
+ * @remarks If an unused uuid is provided in options, it will be used. If no uuid is provided, OpefinFin will assign a uuid.
+ * @example
+ * ```js
+ * fin.System.monitorExternalProcess({
+ * pid: 10208,
+ * uuid: 'my-external-process', // optional
+ * listener: function (result) {
+ * console.log('the exit code', result.exitCode);
+ * }
+ * }).then(processIdentity => console.log(processIdentity)).catch(err => console.log(err));
+ * ```
+ */
+ monitorExternalProcess(options) {
+ return this.sendExternalProcessRequest('monitor-external-process', options);
+ }
+ /**
+ * Writes the passed message into both the log file and the console.
+ * @param level The log level for the entry. Can be either "info", "warning" or "error"
+ * @param message The log message text
+ *
+ * @example
+ * ```js
+ * fin.System.log("info", "An example log message").then(() => console.log('Log info message')).catch(err => console.log(err));
+ * ```
+ */
+ log(level, message) {
+ return this.wire.sendAction('write-to-log', { level, message }).then(() => undefined);
+ }
+ /**
+ * Opens the passed URL in the default web browser.
+ *
+ * @remarks It only supports http(s) and fin(s) protocols by default.
+ * In order to use other custom protocols, they have to be enabled via
+ * [API security settings](https://developers.openfin.co/docs/api-security).
+ * File protocol and file path are not supported.
+ * @param url The URL to open
+ *
+ * @example
+ * ```js
+ * fin.System.openUrlWithBrowser('https://cdn.openfin.co/docs/javascript/stable/tutorial-System.openUrlWithBrowser.html')
+ * .then(() => console.log('Opened URL'))
+ * .catch(err => console.log(err));
+ * ```
+ *
+ * Example of permission definition to enable non-default protocols:
+ *
+ * Note: permission definition should be specified in an app manifest file if there is no DOS settings.
+ * Otherwise it has to be specified in both DOS and app manifest files.
+ *
+ * ```js
+ * "permissions": {
+ * "System": {
+ * "openUrlWithBrowser": {
+ * "enabled": true,
+ * "protocols": [ "msteams", "slack"]
+ * }
+ * }
+ * }
+ * ```
+ */
+ openUrlWithBrowser(url) {
+ return this.wire.sendAction('open-url-with-browser', { url }).then(() => undefined);
+ }
+ /**
+ * Creates a new registry entry under the HKCU root Windows registry key if the given custom protocol name doesn't exist or
+ * overwrites the existing registry entry if the given custom protocol name already exists.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * {@link https://developers.openfin.co/docs/api-security API security settings}. It requires RVM 12 or higher version.
+ *
+ *
+ * @remarks These protocols are reserved and cannot be registered:
+ * - fin
+ * - fins
+ * - openfin
+ * - URI Schemes registered with {@link https://en.wikipedia.org/wiki/List_of_URI_schemes#Official_IANA-registered_schemes IANA}
+ *
+ * @throws if a given custom protocol failed to be registered.
+ * @throws if a manifest URL contains the '%1' string.
+ * @throws if a manifest URL contains a query string parameter which name equals to the Protocol Launch Request Parameter Name.
+ * @throws if the full length of the command string that is to be written to the registry exceeds 2048 bytes.
+ *
+ * @example
+ * ```js
+ * fin.System.registerCustomProtocol({protocolName:'protocol1'}).then(console.log).catch(console.error);
+ * ```
+ */
+ async registerCustomProtocol(options) {
+ if (typeof options !== 'object') {
+ throw new Error('Must provide an object with a `protocolName` property having a string value.');
+ }
+ await this.wire.sendAction('register-custom-protocol', options);
+ }
+ /**
+ * Removes the registry entry for a given custom protocol.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * {@link https://developers.openfin.co/docs/api-security API security settings}. It requires RVM 12 or higher version.
+ *
+ *
+ * @remarks These protocols are reserved and cannot be unregistered:
+ * - fin
+ * - fins
+ * - openfin
+ * - URI Schemes registered with {@link https://en.wikipedia.org/wiki/List_of_URI_schemes#Official_IANA-registered_schemes IANA}
+ *
+ * @throws if a protocol entry failed to be removed in registry.
+ *
+ * @example
+ * ```js
+ * await fin.System.unregisterCustomProtocol('protocol1');
+ * ```
+ */
+ async unregisterCustomProtocol(protocolName) {
+ await this.wire.sendAction('unregister-custom-protocol', { protocolName });
+ }
+ /**
+ * Retrieves the registration state for a given custom protocol.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * {@link https://developers.openfin.co/docs/api-security API security settings}. It requires RVM 12 or higher version.
+ *
+ * @remarks These protocols are reserved and cannot get states for them:
+ * - fin
+ * - fins
+ * - openfin
+ * - URI Schemes registered with {@link https://en.wikipedia.org/wiki/List_of_URI_schemes#Official_IANA-registered_schemes IANA}
+ *
+ *
+ * @example
+ * ```js
+ * const protocolState = await fin.System.getCustomProtocolState('protocol1');
+ */
+ async getCustomProtocolState(protocolName) {
+ return this.wire.sendAction('get-custom-protocol-state', { protocolName }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Removes the process entry for the passed UUID obtained from a prior call
+ * of fin.System.launchExternalProcess().
+ * @param uuid The UUID for a process obtained from a prior call to fin.desktop.System.launchExternalProcess()
+ *
+ * @example
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: "notepad",
+ * listener: function (result) {
+ * console.log("The exit code", result.exitCode);
+ * }
+ * })
+ * .then(identity => fin.System.releaseExternalProcess(identity.uuid))
+ * .then(() => console.log('Process has been unmapped!'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ releaseExternalProcess(uuid) {
+ return this.wire.sendAction('release-external-process', { uuid }).then(() => undefined);
+ }
+ /**
+ * Shows the Chromium Developer Tools for the specified window
+ * @param identity This is a object that is defined by the Identity interface
+ *
+ * @tutorial System.showDeveloperTools
+ */
+ showDeveloperTools(identity) {
+ return this.wire.sendAction('show-developer-tools', identity).then(() => undefined);
+ }
+ /**
+ * Attempt to close an external process. The process will be terminated if it
+ * has not closed after the elapsed timeout in milliseconds.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * API security settings.
+ * @param options A object defined in the TerminateExternalRequestType interface
+ *
+ * @example
+ * ```js
+ * fin.System.launchExternalProcess({
+ * path: "notepad",
+ * listener: function (result) {
+ * console.log("The exit code", result.exitCode);
+ * }
+ * })
+ * .then(identity => fin.System.terminateExternalProcess({uuid: identity.uuid, timeout:2000, killTree: false}))
+ * .then(() => console.log('Terminate the process'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ terminateExternalProcess(options) {
+ return this.wire.sendAction('terminate-external-process', options).then(() => undefined);
+ }
+ /**
+ * Update the OpenFin Runtime Proxy settings.
+ * @param options A config object defined in the ProxyConfig interface
+ *
+ * @example
+ * ```js
+ * fin.System.updateProxySettings({proxyAddress:'127.0.0.1', proxyPort:8080, type:'http'})
+ * .then(() => console.log('Update proxy successfully'))
+ * .catch(err => console.error(err));
+ * ```
+ */
+ updateProxySettings(options) {
+ return this.wire.sendAction('update-proxy', options).then(() => undefined);
+ }
+ /**
+ * Downloads the given application asset.
+ *
+ * Note: This method is restricted by default and must be enabled via
+ * API security settings.
+ * @param appAsset App asset object
+ *
+ * @example
+ * ```js
+ * async function downloadAsset() {
+ * const appAsset = {
+ * src: `${ location.origin }/assets.zip`,
+ * alias: 'dirApp',
+ * version: '1.23.24',
+ * target: 'assets/run.bat'
+ * };
+ *
+ * return fin.System.downloadAsset(appAsset, (progress => {
+ * //Print progress as we download the asset.
+ * const downloadedPercent = Math.floor((progress.downloadedBytes / progress.totalBytes) * 100);
+ * console.log(`Downloaded ${downloadedPercent}%`);
+ * }));
+ * }
+ *
+ * downloadAsset()
+ * .then(() => console.log('Success'))
+ * .catch(err => console.error(err));
+ *
+ * ```
+ */
+ // incompatible with standalone node process.
+ async downloadAsset(appAsset, progressListener) {
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/no-empty-function
+ const noop = () => { };
+ let resolve = noop;
+ let reject = noop;
+ const downloadCompletePromise = new Promise((y, n) => {
+ resolve = y;
+ reject = n;
+ });
+ // node.js environment not supported
+ if (this.wire.environment.constructor.name === 'NodeEnvironment') {
+ throw new transport_errors_1$1.NotSupportedError('downloadAsset only supported in an OpenFin Render process');
+ }
+ const callSite = transport_errors_1$1.RuntimeError.getCallSite();
+ const downloadId = this.wire.environment.getNextMessageId().toString();
+ const dlProgressKey = `asset-download-progress-${downloadId}`;
+ const dlErrorKey = `asset-download-error-${downloadId}`;
+ const dlCompleteKey = `asset-download-complete-${downloadId}`;
+ const dlProgress = (progress) => {
+ const p = {
+ downloadedBytes: progress.downloadedBytes,
+ totalBytes: progress.totalBytes
+ };
+ progressListener(p);
+ };
+ const cleanListeners = () => {
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.removeListener(dlProgressKey, dlProgress);
+ };
+ const dlError = (payload) => {
+ cleanListeners();
+ const { reason, err: error } = payload;
+ reject(new transport_errors_1$1.RuntimeError({ reason, error }, callSite));
+ };
+ const dlComplete = () => {
+ cleanListeners();
+ resolve();
+ };
+ await Promise.all([
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.on(dlProgressKey, dlProgress),
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.once(dlErrorKey, dlError),
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.once(dlCompleteKey, dlComplete)
+ ]);
+ const downloadOptions = Object.assign(appAsset, { downloadId });
+ await this.wire.sendAction('download-asset', downloadOptions).catch((err) => {
+ cleanListeners();
+ throw err;
+ });
+ return downloadCompletePromise;
+ }
+ /**
+ * Downloads a version of the runtime.
+ * @param options - Download options.
+ * @param progressListener - called as the runtime is downloaded with progress information.
+ *
+ * @remarks Only supported in an OpenFin Render process.
+ *
+ * @example
+ * ```js
+ * var downloadOptions = {
+ * //Specific version number required, if given a release channel the call will produce an error.
+ * version: '9.61.30.1'
+ * };
+ *
+ * function onProgress(progress) {
+ * console.log(`${Math.floor((progress.downloadedBytes / progress.totalBytes) * 100)}%`);
+ * }
+ *
+ * fin.System.downloadRuntime(downloadOptions, onProgress).then(() => {
+ * console.log('Download complete');
+ * }).catch(err => {
+ * console.log(`Download Failed, we could retry: ${err.message}`);
+ * console.log(err);
+ * });
+ * ```
+ */
+ downloadRuntime(options, progressListener) {
+ const callsites = transport_errors_1$1.RuntimeError.getCallSite();
+ return new Promise((resolve, reject) => {
+ // node.js environment not supported
+ if (this.wire.environment.constructor.name === 'NodeEnvironment') {
+ reject(new transport_errors_1$1.NotSupportedError('downloadRuntime only supported in an OpenFin Render process'));
+ return;
+ }
+ const downloadId = this.wire.environment.getNextMessageId().toString();
+ const dlProgressKey = `runtime-download-progress-${downloadId}`;
+ const dlErrorKey = `runtime-download-error-${downloadId}`;
+ const dlCompleteKey = `runtime-download-complete-${downloadId}`;
+ const dlProgress = (progress) => {
+ const p = {
+ downloadedBytes: progress.downloadedBytes,
+ totalBytes: progress.totalBytes
+ };
+ progressListener(p);
+ };
+ const cleanListeners = () => {
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.removeListener(dlProgressKey, dlProgress);
+ };
+ const dlError = (payload) => {
+ cleanListeners();
+ const { reason, err: error } = payload;
+ reject(new transport_errors_1$1.RuntimeError({ reason, error }, callsites));
+ };
+ const dlComplete = () => {
+ cleanListeners();
+ resolve();
+ };
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.on(dlProgressKey, dlProgress);
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.once(dlErrorKey, dlError);
+ // TODO: fix internal types
+ // @ts-expect-error
+ this.once(dlCompleteKey, dlComplete);
+ const downloadOptions = Object.assign(options, { downloadId });
+ this.wire.sendAction('download-runtime', downloadOptions).catch((err) => {
+ cleanListeners();
+ reject(err);
+ });
+ });
+ }
+ /**
+ * Download preload scripts from given URLs
+ * @param scripts - URLs of preload scripts.
+ *
+ * @example
+ * ```js
+ * const scripts = [
+ * { url: 'http://.../preload.js' },
+ * { url: 'http://.../preload2.js' }
+ * ];
+ *
+ * fin.System.downloadPreloadScripts(scripts).then(results => {
+ * results.forEach(({url, success, error}) => {
+ * console.log(`URL: ${url}`);
+ * console.log(`Success: ${success}`);
+ * if (error) {
+ * console.log(`Error: ${error}`);
+ * }
+ * });
+ * });
+ * ```
+ */
+ downloadPreloadScripts(scripts) {
+ return this.wire.sendAction('download-preload-scripts', { scripts }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an array of data (name, ids, bounds) for all application windows.
+ *
+ * @example
+ * ```js
+ * fin.System.getAllExternalApplications()
+ * .then(externalApps => console.log('Total external apps: ' + externalApps.length))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ getAllExternalApplications() {
+ return this.wire.sendAction('get-all-external-applications').then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves app asset information.
+ * @param options
+ *
+ * @example
+ * ```js
+ * fin.System.getAppAssetInfo({alias:'procexp'}).then(assetInfo => console.log(assetInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getAppAssetInfo(options) {
+ return this.wire.sendAction('get-app-asset-info', options).then(({ payload }) => payload.data);
+ }
+ /**
+ * Get additional info of cookies.
+ *
+ * @example
+ * ```js
+ * fin.System.getCookies({name: 'myCookie'}).then(cookies => console.log(cookies)).catch(err => console.log(err));
+ * ```
+ */
+ getCookies(options) {
+ const url = this.wire.environment.getUrl();
+ const newOptions = Object.assign(options, { url });
+ return this.wire.sendAction('get-cookies', newOptions).then(({ payload }) => payload.data);
+ }
+ /**
+ * Set the minimum log level above which logs will be written to the OpenFin log
+ * @param The minimum level (inclusive) above which all calls to log will be written
+ *
+ * @example
+ * ```js
+ * fin.System.setMinLogLevel("verbose").then(() => console.log("log level is set to verbose")).catch(err => console.log(err));
+ * ```
+ */
+ setMinLogLevel(level) {
+ return this.wire.sendAction('set-min-log-level', { level }).then(() => undefined);
+ }
+ /**
+ * Retrieves the UUID of the computer on which the runtime is installed
+ * @param uuid The uuid of the running application
+ *
+ * @example
+ * ```js
+ * fin.System.resolveUuid('OpenfinPOC').then(entity => console.log(entity)).catch(err => console.log(err));
+ * ```
+ */
+ resolveUuid(uuid) {
+ return this.wire
+ .sendAction('resolve-uuid', {
+ entityKey: uuid
+ })
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * Retrieves an array of data for all external applications
+ * @param requestingIdentity This object is described in the Identity typedef
+ * @param data Any data type to pass to the method
+ *
+ * @ignore
+ */
+ executeOnRemote(requestingIdentity, data) {
+ data.requestingIdentity = requestingIdentity;
+ return this.wire.ferryAction(data);
+ }
+ /**
+ * Reads the specifed value from the registry.
+ * @remarks This method is restricted by default and must be enabled via
+ * [API security settings](https://developers.openfin.co/docs/api-security).
+ * @param rootKey - The registry root key.
+ * @param subkey - The registry key.
+ * @param value - The registry value name.
+ *
+ * @example
+ * ```js
+ * fin.System.readRegistryValue("HKEY_LOCAL_MACHINE", "HARDWARE\\DESCRIPTION\\System", "BootArchitecture").then(val => console.log(val)).catch(err => console.log(err));
+ * ```
+ *
+ * See {@link https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx here} for Window's error code definitions.
+ *
+ * Example payloads of different registry types:
+ *
+ * See list of types {@link https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx here}.
+ *
+ * ```js
+ * // REG_DWORD
+ * {
+ * data: 1,
+ * rootKey: "HKEY_LOCAL_MACHINE",
+ * subkey: "Foo\Bar",
+ * type: "REG_DWORD",
+ * value: "Baz"
+ * }
+ *
+ * // REG_QWORD
+ * {
+ * data: 13108146671334112,
+ * rootKey: "HKEY_LOCAL_MACHINE",
+ * subkey: "Foo\Bar",
+ * type: "REG_QWORD",
+ * value: "Baz"
+ * }
+ *
+ * // REG_SZ
+ * {
+ * data: "FooBarBaz",
+ * rootKey: "HKEY_LOCAL_MACHINE",
+ * subkey: "Foo\Bar",
+ * type: "REG_SZ",
+ * value: "Baz"
+ * }
+ *
+ * // REG_EXPAND_SZ
+ * {
+ * data: "C:\User\JohnDoe\AppData\Local",
+ * rootKey: "HKEY_CURRENT_USER",
+ * subkey: "Foo\Bar",
+ * type: "REG_EXPAND_SZ",
+ * value: "Baz"
+ * }
+ *
+ * // REG_MULTI_SZ
+ * {
+ * data: [
+ * "Foo",
+ * "Bar",
+ * "Baz"
+ * ],
+ * rootKey: "HKEY_CURRENT_USER",
+ * subkey: "Foo\Bar",
+ * type: "REG_MULTI_SZ",
+ * value: "Baz"
+ * }
+ *
+ * // REG_BINARY
+ * {
+ * data: {
+ * data: [
+ * 255,
+ * 255,
+ * 0,
+ * 43,
+ * 55,
+ * 0,
+ * 0,
+ * 255,
+ * 255
+ * ],
+ * type: "Buffer"
+ * },
+ * rootKey: "HKEY_CURRENT_USER",
+ * subkey: "Foo\Bar",
+ * type: "REG_BINARY",
+ * value: "Baz"
+ * }
+ * ```
+ */
+ readRegistryValue(rootKey, subkey, value) {
+ return this.wire
+ .sendAction('read-registry-value', {
+ rootKey,
+ subkey,
+ value
+ })
+ .then(({ payload }) => payload.data);
+ }
+ /**
+ * This function call will register a unique id and produce a token.
+ * The token can be used to broker an external connection.
+ * @param uuid - A UUID for the remote connection.
+ *
+ * @example
+ * ```js
+ * fin.System.registerExternalConnection("remote-connection-uuid").then(conn => console.log(conn)).catch(err => console.log(err));
+ *
+ *
+ * // object comes back with
+ * // token: "0489EAC5-6404-4F0D-993B-92BB8EAB445D", // this will be unique each time
+ * // uuid: "remote-connection-uuid"
+ *
+ * ```
+ */
+ registerExternalConnection(uuid) {
+ return this.wire.sendAction('register-external-connection', { uuid }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns the json blob found in the [desktop owner settings](https://openfin.co/documentation/desktop-owner-settings/)
+ * for the specified service.
+ * @param serviceIdentifier An object containing a name key that identifies the service.
+ *
+ * @remarks More information about desktop services can be found [here](https://developers.openfin.co/docs/desktop-services).
+ * This call will reject if the desktop owner settings file is not present, not correctly formatted, or if the service requested is not configured or configured incorrectly.
+ *
+ * @example
+ * ```js
+ * // Here we are using the [layouts](https://github.com/HadoukenIO/layouts-service) service.
+ * fin.System.getServiceConfiguration({name:'layouts'}).then(console.log).catch(console.error);
+ * ```
+ */
+ async getServiceConfiguration(serviceIdentifier) {
+ if (typeof serviceIdentifier.name !== 'string') {
+ throw new Error('Must provide an object with a `name` property having a string value');
+ }
+ const { name } = serviceIdentifier;
+ return this.wire.sendAction('get-service-configuration', { name }).then(({ payload }) => payload.data);
+ }
+ async getSystemAppConfig(name) {
+ if (typeof name !== 'string') {
+ throw new Error('Must provide a string value for name of system app');
+ }
+ return this.wire.sendAction('get-system-app-configuration', { name }).then(({ payload }) => payload.data);
+ }
+ /**
+ * Registers a system shutdown handler so user can do some cleanup before system is shutting down.
+ * @remarks Once system shutdown starts, you are unable to cancel it.
+ * @param handler system shutdown handler
+ *
+ * @example
+ * ```js
+ * fin.System.registerShutdownHandler((shutdownEvent) => {
+ * // save state or cleanup
+ * console.log('do some cleanup before shutdown');
+ * // Notify app is ready for termination.
+ * shutdownEvent.proceed();
+ * })
+ * .then(() => console.log('Shutdown handler registered!'))
+ * .catch(err => console.log(err));
+ * ```
+ * @experimental
+ */
+ async registerShutdownHandler(handler) {
+ this.wire.sendAction('system-register-shutdown-handler').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const SystemShutdownEventName = 'system-shutdown';
+ const SystemShutdownHandledEventName = 'system-shutdown-handled';
+ const { uuid, name } = this.wire.me;
+ const shutdownHandler = (payload) => {
+ const proceed = () => {
+ // notify core that the app is ready for shutdown
+ this.wire.environment.raiseEvent(`application/${SystemShutdownHandledEventName}`, {
+ uuid,
+ name,
+ topic: 'application'
+ });
+ };
+ handler({ proceed });
+ };
+ this.on(SystemShutdownEventName, shutdownHandler);
+ }
+ /**
+ * Signals the RVM to perform a health check and returns the results as json.
+ *
+ * @remarks Requires RVM 5.5+
+ *
+ * @example
+ * ```js
+ * try {
+ * const results = await fin.System.runRvmHealthCheck();
+ * console.log(results);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * ```
+ */
+ runRvmHealthCheck() {
+ return this.wire.sendAction('run-rvm-health-check').then(({ payload }) => payload.data);
+ }
+ /**
+ * Launch application using a manifest URL/path. It differs from Application.startFromManifest in that this API can accept a manifest using the fin protocol.
+ * @param manifestUrl - The manifest's URL or path.
+ * @param opts - Parameters that the RVM will use.
+ *
+ * @experimental
+ * @remarks Supports protocols http/s and fin/s, and also a local path.
+ *
+ * Note: This API is Windows only.
+ *
+ * @example
+ *
+ * This API can handle most manifest types. Some examples below.
+ *
+ * Traditional:
+ * ```js
+ * const manifest = await fin.System.launchManifest(
+ * 'https://demoappdirectory.openf.in/desktop/config/apps/OpenFin/HelloOpenFin/app.json');
+ * console.log(manifest);
+ * ```
+ *
+ * Platform:
+ * ```js
+ * const manifest = await fin.System.launchManifest('https://openfin.github.io/platform-api-project-seed/public.json');
+ * console.log(manifest);
+ * ```
+ *
+ * Launching traditional manifest into a platform:
+ * ```js
+ * const manifest = await fin.System.launchManifest(
+ * 'https://openfin.github.io/platform-api-project-seed/public.json?\
+ * $$appManifestUrl=https://demoappdirectory.openf.in/desktop/config/\
+ * apps/OpenFin/HelloOpenFin/app.json');
+ * console.log(manifest);
+ * ```
+ *
+ * Launching with RVM options:
+ * ```js
+ * const manifest = await fin.System.launchManifest('https://openfin.github.io/platform-api-project-seed/public.json',
+ * { noUi: true, userAppConfigArgs: { abc: '123', xyz: '789' } });
+ * console.log(manifest);
+ * ```
+ *
+ * Local Path:
+ * ```js
+ * const manifest = await fin.System.launchManifest('file://c:\\path\\to\\manifest\\file.json');
+ * console.log(manifest);
+ * ```
+ *
+ * Launching with RVM 'subscribe' option:
+ *
+ * This option allows users to subscribe to app version resolver events when
+ * calling launchManifest with fallbackManifests specified.
+ *
+ * ```js
+ * fin.System.launchManifest('fins://system-apps/notifications/app.json', { subscribe: (launch) => {
+ * launch.on('app-version-progress', (progress) => {
+ * console.log("Trying manifest " + progress.manifest)
+ * });
+ *
+ * launch.on('runtime-status', (status) => {
+ * console.log("Runtime status: " + JSON.stringify(status));
+ * });
+ *
+ * // RVM has successfully found the target runtime version
+ * launch.on('app-version-complete', (complete) => {
+ * console.log("Parent app " + complete.srcManifest + " resolved to " + complete.manifest);
+ * launch.removeAllListeners();
+ * });
+ *
+ * // RVM failed to find an available runtime version
+ * launch.on('app-version-error', (error) => {
+ * console.log("Failed to resolve " + error.srcManifest + " from the fallbackManifests");
+ * launch.removeAllListeners();
+ * });
+ * }
+ * });
+ * ```
+ */
+ async launchManifest(manifestUrl, opts = {}) {
+ const { subscribe, ..._sendOpts } = opts;
+ const sendOpts = _sendOpts;
+ if (subscribe) {
+ const launchEmitter = new events_1$6.EventEmitter();
+ subscribe(launchEmitter);
+ const AppVersionProgressEventName = 'app-version-progress';
+ const RuntimeStatusEventName = 'runtime-status';
+ const AppVersionCompleteEventName = 'app-version-complete';
+ const AppVersionErrorEventName = 'app-version-error';
+ // add id to avoid multiple api calls getting duplicated events
+ const id = this.wire.environment.getNextMessageId().toString();
+ sendOpts.appVersionId = id;
+ const supportedEvents = [
+ AppVersionCompleteEventName,
+ AppVersionProgressEventName,
+ RuntimeStatusEventName,
+ AppVersionErrorEventName
+ ];
+ const cleanEventPayload = (payload) => {
+ // We need to do type castings below to make sure the return type is correct.
+ const { appVersionId, topic, type: typeWithId, ...rest } = payload;
+ const type = supportedEvents.find((x) => typeWithId.includes(x));
+ return {
+ ...rest,
+ type
+ };
+ };
+ const appVersionListener = (payload) => {
+ const cleanPayload = cleanEventPayload(payload);
+ launchEmitter.emit(cleanPayload.type, cleanPayload);
+ };
+ const removeAllListeners = () => {
+ this.removeListener(`${AppVersionProgressEventName}.${id}`, appVersionListener);
+ this.removeListener(`${RuntimeStatusEventName}.${id}`, appVersionListener);
+ this.removeListener(`${AppVersionCompleteEventName}.${id}`, appVersionListener);
+ this.removeListener(`${AppVersionErrorEventName}.${id}`, appVersionListener);
+ this.removeListener(`${AppVersionCompleteEventName}.${id}`, removeAllListeners);
+ this.removeListener(`${AppVersionErrorEventName}.${id}`, removeAllListeners);
+ };
+ await Promise.all([
+ this.on(`${AppVersionProgressEventName}.${id}`, appVersionListener),
+ this.on(`${RuntimeStatusEventName}.${id}`, appVersionListener),
+ this.once(`${AppVersionCompleteEventName}.${id}`, appVersionListener),
+ this.once(`${AppVersionErrorEventName}.${id}`, appVersionListener),
+ this.once(`${AppVersionCompleteEventName}.${id}`, removeAllListeners),
+ this.once(`${AppVersionErrorEventName}.${id}`, removeAllListeners)
+ ]);
+ }
+ const response = await this.wire.sendAction('launch-manifest', {
+ manifestUrl,
+ opts: sendOpts
+ });
+ return response.payload.data.manifest;
+ }
+ /**
+ * Query permission of a secured api in current context.
+ * @param apiName - The full name of a secured API.
+ *
+ * @example
+ * ```js
+ * fin.System.queryPermissionForCurrentContext('System.launchExternalProcess').then(result => console.log(result)).catch(err => console.log(err));
+ *
+ * //This response has the following shape:
+ * {
+ * permission: 'System.launchExternalProcess', // api full name
+ * state: 'granted', // state of permission
+ * granted: true
+ * }
+ * ```
+ */
+ async queryPermissionForCurrentContext(apiName) {
+ const identity = { uuid: this.wire.me.uuid, name: this.wire.me.name };
+ const response = await this.wire.sendAction('query-permission-for-current-context', {
+ apiName,
+ identity
+ });
+ return response.payload.data;
+ }
+ // Not documenting, internal use only.
+ async enableNativeWindowIntegrationProvider(permissions) {
+ const { payload } = await this.wire.sendAction('enable-native-window-integration-provider', { permissions });
+ return payload.data;
+ }
+ /**
+ * (Internal) Register the usage of a component with a platform
+ * @param options - Object with data and type
+ *
+ * @example
+ * ```js
+ * async function registerUsage() {
+ * const app = await fin.System.getCurrent();
+ * return await fin.System.registerUsage({
+ * type: 'workspace-licensing',
+ * // example values for the following data object
+ * data: {
+ * apiVersion: '1.0',
+ * componentName: 'home',
+ * componentVersion: '1.0',
+ * allowed: true,
+ * rejectionCode: ''
+ * }
+ * });
+ * }
+ *
+ * registerUsage().then(() => console.log('Successfully registered component application')).catch(err => console.log(err));
+ * ```
+ */
+ async registerUsage({ data, type }) {
+ await this.wire.sendAction('register-usage', { data, type });
+ }
+ /**
+ * Returns an array with all printers of the caller and not all the printers on the desktop.
+ *
+ * @example
+ * ```js
+ * fin.System.getPrinters()
+ * .then((printers) => {
+ * printers.forEach((printer) => {
+ * if (printer.isDefault) {
+ * console.log(printer);
+ * }
+ * });
+ * })
+ * .catch((err) => {
+ * console.log(err);
+ * });
+ * ```
+ */
+ async getPrinters() {
+ const { payload } = await this.wire.sendAction('system-get-printers');
+ return payload.data;
+ }
+ /**
+ * Updates Process Logging values: periodic interval and outlier detection entries and interval.
+ * @param options Process Logging updatable options.
+ *
+ * @remarks When enabling verbose mode, additional process information is logged to the debug.log:
+ *
+ * 1. Periodically process usage (memory, cpu, etc) will be logged for each PID along with the windows, views and
+ * iframes that belong to them. The default is every 30 seconds. Updatable by passing the interval option.
+ * 2. When Windows and Views are created or navigated the PID they belong to and their options will be logged.
+ * 3. When Windows and Views are destroyed their last known process usage will be logged.
+ * 4. Whenever an outlier memory usage is detected it will be logged. By default, on an interval of 5 seconds we will
+ * collect process usage for all PIDs and when 144 such entries are collected, we will start analyzing the data for any
+ * possible outliers in the following entries. The interval and maximum number of entries stored in the running buffer
+ * can be updatable by passing the outlierDetection.interval and outlierDetection.entries options.
+ *
+ * @example
+ *
+ * ```js
+ * await fin.System.updateProcessLoggingOptions({
+ * interval: 10,
+ * outlierDetection: {
+ * interval: 15,
+ * entries: 200
+ * }
+ * });
+ * ```
+ */
+ async updateProcessLoggingOptions(options) {
+ await this.wire.sendAction('system-update-process-logging-options', { options });
+ }
+ /**
+ * Returns domain settings for the current application.
+ * Initial settings are configured with the defaultDomainSettings application option via manifest.
+ * Domain settings can be overwritten during runtime with System.setDomainSettings.
+ * @example
+ * ```js
+ * const domainSettings = await fin.System.getDomainSettings();
+ * // {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // "https://openfin.co"
+ * // ],
+ * // "options": {
+ * // "downloadSettings": {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // ""
+ * // ],
+ * // "behavior": "prompt"
+ * // }
+ * // ]
+ * // }
+ * // }
+ * // }
+ * // ]
+ * // }
+ * ```
+ */
+ async getDomainSettings() {
+ const { payload: { data } } = await this.wire.sendAction('get-domain-settings', this.identity);
+ return data;
+ }
+ /**
+ * Sets the domain settings for the current application.
+ * @param domainSettings - domain settings object
+ * @example
+ * ```js
+ * const domainSettings = await fin.System.getDomainSettings();
+ * // {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // "https://openfin.co"
+ * // ],
+ * // "options": {
+ * // "downloadSettings": {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // ""
+ * // ],
+ * // "behavior": "prompt"
+ * // }
+ * // ]
+ * // }
+ * // }
+ * // }
+ * // ]
+ * // }
+ *
+ * // Valid rule behaviors are 'prompt' and 'no-prompt'
+ * domainSettings.rules[0].options.downloadSettings.rules[0].behavior = 'no-prompt';
+ *
+ * await fin.System.setDomainSettings(domainSettings);
+ *
+ * const newDomainSettings = await fin.System.getDomainSettings();
+ * // {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // "https://openfin.co"
+ * // ],
+ * // "options": {
+ * // "downloadSettings": {
+ * // "rules": [
+ * // {
+ * // "match": [
+ * // ""
+ * // ],
+ * // "behavior": "no-prompt"
+ * // }
+ * // ]
+ * // }
+ * // }
+ * // }
+ * // ]
+ * // }
+ * ```
+ */
+ async setDomainSettings(domainSettings) {
+ await this.wire.sendAction('set-domain-settings', { domainSettings, ...this.identity });
+ }
+}
+system.System = System;
+
+var interappbus = {};
+
+var refCounter = {};
+
+Object.defineProperty(refCounter, "__esModule", { value: true });
+refCounter.RefCounter = void 0;
+class RefCounter {
+ constructor() {
+ this.topicRefMap = new Map();
+ }
+ // returns the ref count after incrementing
+ incRefCount(key) {
+ const refCount = this.topicRefMap.get(key);
+ let returnCount;
+ if (!refCount) {
+ this.topicRefMap.set(key, 1);
+ returnCount = 1;
+ }
+ else {
+ const newRefCount = refCount + 1;
+ returnCount = newRefCount;
+ this.topicRefMap.set(key, newRefCount);
+ }
+ return returnCount;
+ }
+ // returns the ref count after decrementing, or -1 if the key already had no references
+ decRefCount(key) {
+ const refCount = this.topicRefMap.get(key);
+ let returnCount;
+ if (refCount) {
+ const newRefCount = refCount - 1;
+ this.topicRefMap.set(key, newRefCount);
+ returnCount = newRefCount;
+ }
+ else {
+ returnCount = -1;
+ }
+ return returnCount;
+ }
+ // Execute firstAction if it is the first such ref, else execute nonFirstAction.
+ // In either case the return value is that of the action executed
+ actOnFirst(key, firstAction, nonFirstAction) {
+ const numRefs = this.incRefCount(key);
+ const isFirstRef = numRefs === 1;
+ return isFirstRef ? firstAction() : nonFirstAction();
+ }
+ // Execute lastAction if it is the first such ref, else execute nonLastAction.
+ // In either case the return value is that of the action executed
+ actOnLast(key, lastAction, nonLastAction) {
+ const numRefs = this.decRefCount(key);
+ const isLastRef = numRefs === 0;
+ return isLastRef ? lastAction() : nonLastAction();
+ }
+}
+refCounter.RefCounter = RefCounter;
+
+var channel$1 = {};
+
+var client = {};
+
+var channel = {};
+
+Object.defineProperty(channel, "__esModule", { value: true });
+channel.ChannelBase = channel.ProtectedItems = void 0;
+const resultOrPayload = (func) => async (topic, payload, senderIdentity) => {
+ const res = await func(topic, payload, senderIdentity);
+ return res === undefined ? payload : res;
+};
+class ProtectedItems {
+ /**
+ * @internal
+ */
+ constructor(providerIdentity, wire) {
+ this.providerIdentity = providerIdentity;
+ this.wire = wire;
+ }
+}
+channel.ProtectedItems = ProtectedItems;
+class ChannelBase {
+ static defaultAction(topic) {
+ throw new Error(`No action registered at target for ${topic}`);
+ }
+ constructor() {
+ this.subscriptions = new Map();
+ }
+ async processAction(topic, payload, senderIdentity) {
+ try {
+ const mainAction = this.subscriptions.has(topic)
+ ? this.subscriptions.get(topic)
+ : (currentPayload, id) => (this.defaultAction ?? ChannelBase.defaultAction)(topic, currentPayload, id);
+ const preActionProcessed = this.preAction ? await this.preAction(topic, payload, senderIdentity) : payload;
+ const actionProcessed = await mainAction(preActionProcessed, senderIdentity);
+ return this.postAction ? await this.postAction(topic, actionProcessed, senderIdentity) : actionProcessed;
+ }
+ catch (e) {
+ if (this.errorMiddleware) {
+ return this.errorMiddleware(topic, e, senderIdentity);
+ }
+ throw e;
+ }
+ }
+ /**
+ * Register middleware that fires before the action.
+ *
+ * @param func
+ *
+ * @example
+ *
+ * Channel Provider:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * provider.register('provider-action', (payload, identity) => {
+ * console.log(payload, identity);
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * provider.beforeAction((action, payload, identity) => {
+ * //The payload can be altered here before handling the action.
+ * payload.received = Date.now();
+ * return payload;
+ * });
+ *
+ * })();
+ * ```
+ *
+ * Channel Client:
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * client.register('client-action', (payload, identity) => {
+ * console.log(payload, identity);
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * client.beforeAction((action, payload, identity) => {
+ * //The payload can be altered here before handling the action.
+ * payload.received = Date.now();
+ * return payload;
+ * });
+ *
+ * const providerResponse = await client.dispatch('provider-action', { message: 'Hello From the client' });
+ * console.log(providerResponse);
+ * })();
+ * ```
+ */
+ beforeAction(func) {
+ if (this.preAction) {
+ throw new Error('Already registered beforeAction middleware');
+ }
+ this.preAction = resultOrPayload(func);
+ }
+ /**
+ * Register an error handler. This is called before responding on any error.
+ *
+ * @param func
+ *
+ * Channel Provider:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * provider.register('provider-action', (payload, identity) => {
+ * console.log(payload);
+ * throw new Error('Action error');
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * provider.onError((action, error, identity) => {
+ * console.log('uncaught Exception in action:', action);
+ * console.error(error);
+ * });
+ *
+ * })();
+ * ```
+ *
+ * Channel Client:
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * client.register('client-action', (payload, identity) => {
+ * console.log(payload);
+ * throw new Error('Action error');
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * client.onError((action, error, identity) => {
+ * console.log('uncaught Exception in action:', action);
+ * console.error(error);
+ * });
+ * })();
+ * ```
+ */
+ onError(func) {
+ if (this.errorMiddleware) {
+ throw new Error('Already registered error middleware');
+ }
+ this.errorMiddleware = func;
+ }
+ /**
+ * Register middleware that fires after the action.
+ *
+ * @param func
+ *
+ * @remarks If the action does not return the payload, then the afterAction will not have access to the payload object.
+ *
+ * @example
+ *
+ * Channel Provider:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.register('provider-action', (payload, identity) => {
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * await provider.afterAction((action, payload, identity) => {
+ * //the payload can be altered here after handling the action but before sending an acknowledgement.
+ * payload.sent = date.now();
+ * return payload;
+ * });
+ *
+ * })();
+ * ```
+ *
+ * Channel Client:
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.register('client-action', (payload, identity) => {
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * await client.afterAction((action, payload, identity) => {
+ * //the payload can be altered here after handling the action but before sending an acknowledgement.
+ * payload.sent = date.now();
+ * return payload;
+ * });
+ *
+ * })();
+ * ```
+ */
+ afterAction(func) {
+ if (this.postAction) {
+ throw new Error('Already registered afterAction middleware');
+ }
+ this.postAction = resultOrPayload(func);
+ }
+ /**
+ * Remove an action by action name.
+ *
+ * @param action
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.register('provider-action', (payload, identity) => {
+ * console.log(payload);
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * await provider.remove('provider-action');
+ *
+ * })();
+ * ```
+ */
+ remove(action) {
+ this.subscriptions.delete(action);
+ }
+ /**
+ * Registers a default action. This is used any time an action that has not been registered is invoked.
+ *
+ * @example
+ *
+ * Channel Provider:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.setDefaultAction((action, payload, identity) => {
+ * console.log(`Client with identity ${JSON.stringify(identity)} has attempted to dispatch unregistered action: ${action}.`);
+ *
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * })();
+ * ```
+ *
+ * Channel Client:
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.setDefaultAction((action, payload, identity) => {
+ * console.log(`Provider with identity ${JSON.stringify(identity)} has attempted to dispatch unregistered action: ${action}.`);
+ *
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * })();
+ * ```
+ * @param func
+ */
+ setDefaultAction(func) {
+ if (this.defaultAction) {
+ throw new Error('default action can only be set once');
+ }
+ else {
+ this.defaultAction = func;
+ }
+ }
+ /**
+ * Register an action to be called by dispatching from any channelClient or channelProvider.
+ *
+ * @param topic
+ * @param listener
+ *
+ * @remarks The return value will be sent back as an acknowledgement to the original caller. You can throw an
+ * error to send a negative-acknowledgement and the error will reject the promise returned to the sender by the
+ * dispatch call. Once a listener is registered for a particular action, it stays in place receiving and responding
+ * to incoming messages until it is removed. This messaging mechanism works exactly the same when messages are
+ * dispatched from the provider to a client. However, the provider has an additional publish method that sends messages
+ * to all connected clients.
+ *
+ * Because multiple clients can share the same `name` and `uuid`, in order to distinguish between individual clients,
+ * the `identity` argument in a provider's registered action callback contains an `endpointId` property. When dispatching
+ * from a provider to a client, the `endpointId` property must be provided in order to send an action to a specific client.
+ *
+ * @example
+ *
+ * Channel Provider:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.register('provider-action', (payload, identity) => {
+ * console.log('Action dispatched by client: ', identity);
+ * console.log('Payload sent in dispatch: ', payload);
+ *
+ * return { echo: payload };
+ * });
+ * })();
+ * ```
+ *
+ * Channel Client:
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.register('client-action', (payload, identity) => {
+ * console.log('Action dispatched by client: ', identity);
+ * console.log('Payload sent in dispatch: ', payload);
+ *
+ * return { echo: payload };
+ * });
+ * })();
+ * ```
+ */
+ register(topic, listener) {
+ if (this.subscriptions.has(topic)) {
+ throw new Error(`Subscription already registered for action: ${topic}. Unsubscribe before adding new subscription`);
+ }
+ else {
+ this.subscriptions.set(topic, listener);
+ return true;
+ }
+ }
+}
+channel.ChannelBase = ChannelBase;
+
+var __classPrivateFieldGet$d = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __classPrivateFieldSet$b = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var _ChannelClient_protectedObj, _ChannelClient_strategy, _ChannelClient_close;
+Object.defineProperty(client, "__esModule", { value: true });
+client.ChannelClient = void 0;
+const channel_1$1 = channel;
+const channelClientsByEndpointId = new Map();
+/**
+ * Instance created to enable use of a channel as a client. Allows for communication with the
+ * {@link ChannelProvider ChannelProvider} by invoking an action on the
+ * provider via {@link ChannelClient#dispatch dispatch} and to listen for communication
+ * from the provider by registering an action via {@link ChannelClient#register register}.
+ *
+ * ### Synchronous Methods:
+ * * {@link ChannelClient#onDisconnection onDisconnection(listener)}
+ * * {@link ChannelClient#register register(action, listener)}
+ * * {@link ChannelClient#remove remove(action)}
+ *
+ * ### Asynchronous Methods:
+ * * {@link ChannelClient#disconnect disconnect()}
+ * * {@link ChannelClient#dispatch dispatch(action, payload)}
+ *
+ * ### Middleware:
+ * Middleware functions receive the following arguments: (action, payload, senderId).
+ * The return value of the middleware function will be passed on as the payload from beforeAction, to the action listener, to afterAction
+ * unless it is undefined, in which case the original payload is used. Middleware can be used for side effects.
+ * * {@link ChannelClient#setDefaultAction setDefaultAction(middleware)}
+ * * {@link ChannelClient#onError onError(middleware)}
+ * * {@link ChannelClient#beforeAction beforeAction(middleware)}
+ * * {@link ChannelClient#afterAction afterAction(middleware)}
+ */
+class ChannelClient extends channel_1$1.ChannelBase {
+ /**
+ * @internal
+ */
+ static closeChannelByEndpointId(id) {
+ const channel = channelClientsByEndpointId.get(id);
+ if (channel) {
+ __classPrivateFieldGet$d(channel, _ChannelClient_close, "f").call(channel);
+ }
+ }
+ /**
+ * @internal
+ * closes the corresponding channel and invokes the disconnect listener if an event payload is passed.
+ */
+ static handleProviderDisconnect(eventPayload) {
+ for (const channelClient of channelClientsByEndpointId.values()) {
+ if (channelClient.providerIdentity.channelId === eventPayload.channelId) {
+ channelClient.disconnectListener(eventPayload);
+ __classPrivateFieldGet$d(channelClient, _ChannelClient_close, "f").call(channelClient);
+ }
+ }
+ }
+ /**
+ * @internal
+ */
+ constructor(routingInfo, wire, strategy) {
+ super();
+ _ChannelClient_protectedObj.set(this, void 0);
+ _ChannelClient_strategy.set(this, void 0);
+ // needs to be bound;
+ this.processAction = (action, payload, senderIdentity) => super.processAction(action, payload, senderIdentity);
+ _ChannelClient_close.set(this, () => {
+ channelClientsByEndpointId.delete(this.endpointId);
+ __classPrivateFieldGet$d(this, _ChannelClient_strategy, "f").close();
+ });
+ __classPrivateFieldSet$b(this, _ChannelClient_protectedObj, new channel_1$1.ProtectedItems(routingInfo, wire), "f");
+ this.disconnectListener = () => undefined;
+ this.endpointId = routingInfo.endpointId;
+ __classPrivateFieldSet$b(this, _ChannelClient_strategy, strategy, "f");
+ channelClientsByEndpointId.set(this.endpointId, this);
+ strategy.receive(this.processAction);
+ }
+ /**
+ * a read-only provider identity
+ */
+ get providerIdentity() {
+ const protectedObj = __classPrivateFieldGet$d(this, _ChannelClient_protectedObj, "f");
+ return protectedObj.providerIdentity;
+ }
+ /**
+ * Dispatch the given action to the channel provider. Returns a promise that resolves with the response from
+ * the provider for that action.
+ *
+ * @param action
+ * @param payload
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.register('client-action', (payload, identity) => {
+ * console.log(payload, identity);
+ * return {
+ * echo: payload
+ * };
+ * });
+ *
+ * const providerResponse = await client.dispatch('provider-action', { message: 'Hello From the client'});
+ * console.log(providerResponse);
+ * })();
+ * ```
+ */
+ async dispatch(action, payload) {
+ if (__classPrivateFieldGet$d(this, _ChannelClient_strategy, "f").isEndpointConnected(this.providerIdentity.channelId)) {
+ return __classPrivateFieldGet$d(this, _ChannelClient_strategy, "f").send(this.providerIdentity.channelId, action, payload);
+ }
+ throw new Error('The client you are trying to dispatch from is disconnected from the target provider.');
+ }
+ /**
+ * Register a listener that is called on provider disconnection. It is passed the disconnection event of the
+ * disconnecting provider.
+ *
+ * @param listener
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.onDisconnection(evt => {
+ * console.log('Provider disconnected', `uuid: ${evt.uuid}, name: ${evt.name}`);
+ * });
+ * })();
+ * ```
+ */
+ onDisconnection(listener) {
+ this.disconnectListener = (payload) => {
+ try {
+ listener(payload);
+ }
+ catch (err) {
+ throw new Error(`Error while calling the onDisconnection callback: ${err.message}`);
+ }
+ finally {
+ this.disconnectListener = () => undefined;
+ }
+ };
+ }
+ /**
+ * Disconnects the client from the channel.
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const client = await fin.InterApplicationBus.Channel.connect('channelName');
+ *
+ * await client.disconnect();
+ * })();
+ * ```
+ */
+ async disconnect() {
+ await this.sendDisconnectAction();
+ __classPrivateFieldGet$d(this, _ChannelClient_close, "f").call(this);
+ }
+ async sendDisconnectAction() {
+ const protectedObj = __classPrivateFieldGet$d(this, _ChannelClient_protectedObj, "f");
+ const { channelName, uuid, name } = protectedObj.providerIdentity;
+ await protectedObj.wire.sendAction('disconnect-from-channel', {
+ channelName,
+ uuid,
+ name,
+ endpointId: this.endpointId
+ });
+ }
+}
+client.ChannelClient = ChannelClient;
+_ChannelClient_protectedObj = new WeakMap(), _ChannelClient_strategy = new WeakMap(), _ChannelClient_close = new WeakMap();
+
+var connectionManager = {};
+
+var exhaustive = {};
+
+Object.defineProperty(exhaustive, "__esModule", { value: true });
+exhaustive.exhaustiveCheck = void 0;
+function exhaustiveCheck(value, allowed) {
+ throw new Error(`Unsupported value: ${value}${allowed ? `\n Supported values are: ${allowed.join('')}` : ''}`);
+}
+exhaustive.exhaustiveCheck = exhaustiveCheck;
+
+var strategy$2 = {};
+
+var __classPrivateFieldSet$a = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$c = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _ClassicStrategy_wire, _ClassicStrategy_endpointIdentityMap, _ClassicStrategy_pendingMessagesByEndpointId;
+Object.defineProperty(strategy$2, "__esModule", { value: true });
+strategy$2.ClassicInfo = strategy$2.ClassicStrategy = void 0;
+/*
+This is used to abstract out ipc messaging from the channels implementation. It is only concerned with sending messages and registration with the MessageReceiver
+*/
+class ClassicStrategy {
+ constructor(wire, messageReceiver, endpointId, // Provider endpointId is channelId
+ providerIdentity) {
+ this.messageReceiver = messageReceiver;
+ this.endpointId = endpointId;
+ this.providerIdentity = providerIdentity;
+ _ClassicStrategy_wire.set(this, void 0);
+ // Store full endpointIdentity by endpointId of all known endpoints for this strategy instance.
+ // (clients will only have 1: the provider, the provider will have all clients)
+ _ClassicStrategy_endpointIdentityMap.set(this, new Map());
+ // Store a set of cancellable promises to be able to reject them when client
+ // connection problems occur
+ _ClassicStrategy_pendingMessagesByEndpointId.set(this, new Map);
+ this.send = async (endpointId, action, payload) => {
+ const to = __classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").get(endpointId);
+ if (!to) {
+ throw new Error(`Could not locate routing info for endpoint ${endpointId}`);
+ }
+ // as casting to any because typescript complains. The following is only relevant if this is a locally set endpointId on a ClientIdentity.
+ // We delete these properties to not change backwards compatibility.
+ const cleanId = { ...to };
+ if (cleanId.isLocalEndpointId) {
+ delete cleanId.endpointId;
+ }
+ delete cleanId.isLocalEndpointId;
+ // grab the promise before awaiting it to save in our pending messages map
+ const p = __classPrivateFieldGet$c(this, _ClassicStrategy_wire, "f")
+ .sendAction('send-channel-message', {
+ ...cleanId,
+ providerIdentity: this.providerIdentity,
+ action,
+ payload
+ });
+ __classPrivateFieldGet$c(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId)?.add(p);
+ const raw = await p.catch((error) => {
+ throw new Error(error.message);
+ }).finally(() => {
+ // clean up the pending promise
+ __classPrivateFieldGet$c(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId)?.delete(p);
+ });
+ return raw.payload.data.result;
+ };
+ this.close = async () => {
+ this.messageReceiver.removeEndpoint(this.providerIdentity.channelId, this.endpointId);
+ [...__classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").keys()].forEach((id) => this.closeEndpoint(id));
+ __classPrivateFieldSet$a(this, _ClassicStrategy_endpointIdentityMap, new Map(), "f");
+ };
+ __classPrivateFieldSet$a(this, _ClassicStrategy_wire, wire, "f");
+ }
+ onEndpointDisconnect(endpointId, listener) {
+ // Never fires for 'classic'.
+ }
+ receive(listener) {
+ this.messageReceiver.addEndpoint(listener, this.providerIdentity.channelId, this.endpointId);
+ }
+ async closeEndpoint(endpointId) {
+ const id = __classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").get(endpointId);
+ __classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").delete(endpointId);
+ const pendingSet = __classPrivateFieldGet$c(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId);
+ pendingSet?.forEach((p) => {
+ const errorMsg = `Channel connection with identity uuid: ${id?.uuid} / name: ${id?.name} / endpointId: ${endpointId} no longer connected.`;
+ p.cancel(new Error(errorMsg));
+ });
+ }
+ isEndpointConnected(endpointId) {
+ return __classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").has(endpointId);
+ }
+ addEndpoint(endpointId, payload) {
+ __classPrivateFieldGet$c(this, _ClassicStrategy_endpointIdentityMap, "f").set(endpointId, payload.endpointIdentity);
+ __classPrivateFieldGet$c(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").set(endpointId, new Set());
+ }
+ isValidEndpointPayload(payload) {
+ return (typeof payload?.endpointIdentity?.endpointId === 'string' ||
+ typeof payload?.endpointIdentity?.channelId === 'string');
+ }
+}
+strategy$2.ClassicStrategy = ClassicStrategy;
+_ClassicStrategy_wire = new WeakMap(), _ClassicStrategy_endpointIdentityMap = new WeakMap(), _ClassicStrategy_pendingMessagesByEndpointId = new WeakMap();
+// Arbitrarily starting at 5 to leave the door open to backfilling pre endpointId etc.
+strategy$2.ClassicInfo = { version: 5, minimumVersion: 0, type: 'classic' };
+
+var strategy$1 = {};
+
+var endpoint = {};
+
+var errors = {};
+
+Object.defineProperty(errors, "__esModule", { value: true });
+errors.errorToPOJO = void 0;
+function errorToPOJO(error) {
+ return {
+ stack: error.stack,
+ name: error.name,
+ message: error.message,
+ toString: error.toString
+ };
+}
+errors.errorToPOJO = errorToPOJO;
+
+var __classPrivateFieldGet$b = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __classPrivateFieldSet$9 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var _RTCEndpoint_processAction, _RTCEndpoint_disconnectListener;
+Object.defineProperty(endpoint, "__esModule", { value: true });
+endpoint.RTCEndpoint = void 0;
+/* eslint-disable @typescript-eslint/no-unused-vars */
+const errors_1$1 = errors;
+/*
+This handles sending RTC messages between RTC connections over the request and response data channels.
+*/
+class RTCEndpoint {
+ constructor(rtc, endpointIdentity) {
+ this.rtc = rtc;
+ this.endpointIdentity = endpointIdentity;
+ this.responseMap = new Map();
+ _RTCEndpoint_processAction.set(this, null);
+ _RTCEndpoint_disconnectListener.set(this, void 0);
+ this.connectionStateChangeHandler = (event) => {
+ if (this.rtc.rtcClient.connectionState !== 'connected') {
+ this.rtc.rtcClient.removeEventListener('connectionstatechange', this.connectionStateChangeHandler);
+ this.close();
+ if (__classPrivateFieldGet$b(this, _RTCEndpoint_disconnectListener, "f")) {
+ __classPrivateFieldGet$b(this, _RTCEndpoint_disconnectListener, "f").call(this);
+ }
+ }
+ };
+ this.send = async (action, payload) => {
+ const messageId = `message-${Math.random()}`;
+ const promise = new Promise((resolve, reject) => {
+ this.responseMap.set(messageId, { resolve, reject });
+ });
+ this.rtc.channels.request.send(JSON.stringify({ action, payload, messageId }));
+ return promise;
+ };
+ this.close = () => {
+ this.responseMap.forEach((response) => response.reject('Connection has closed.'));
+ this.responseMap = new Map();
+ this.rtc.channels.request.close();
+ this.rtc.channels.response.close();
+ this.rtc.rtcClient.close();
+ };
+ this.rtc.channels.response.addEventListener('message', (e) => {
+ let { data } = e;
+ if (e.data instanceof ArrayBuffer) {
+ data = new TextDecoder().decode(e.data);
+ }
+ const { messageId, payload, success, error } = JSON.parse(data);
+ const { resolve, reject } = this.responseMap.get(messageId) ?? {};
+ if (resolve && reject) {
+ this.responseMap.delete(messageId);
+ if (success) {
+ resolve(payload);
+ }
+ else {
+ reject(error);
+ }
+ }
+ else {
+ console.log('Could not find id in responseMap.');
+ console.log(e);
+ }
+ });
+ this.rtc.channels.request.addEventListener('message', async (e) => {
+ let { data } = e;
+ if (e.data instanceof ArrayBuffer) {
+ data = new TextDecoder().decode(e.data);
+ }
+ const { messageId, action, payload } = JSON.parse(data);
+ if (__classPrivateFieldGet$b(this, _RTCEndpoint_processAction, "f")) {
+ try {
+ const res = await __classPrivateFieldGet$b(this, _RTCEndpoint_processAction, "f").call(this, action, payload, endpointIdentity);
+ this.rtc.channels.response.send(JSON.stringify({
+ messageId,
+ payload: res,
+ success: true
+ }));
+ }
+ catch (error) {
+ // Check if RTCDataChannel is open before sending, error gets swallowed here in the case where
+ // client dispatched then closed or disconnected before the dispatch resolves.
+ if (this.rtc.channels.response.readyState === 'open') {
+ this.rtc.channels.response.send(JSON.stringify({
+ messageId,
+ error: (0, errors_1$1.errorToPOJO)(error),
+ success: false
+ }));
+ }
+ }
+ // Check if RTCDataChannel is open for same reason as catch block above.
+ }
+ else if (this.rtc.channels.response.readyState === 'open') {
+ this.rtc.channels.response.send(JSON.stringify({
+ messageId,
+ success: false,
+ error: 'Connection not ready.'
+ }));
+ }
+ });
+ this.rtc.rtcClient.addEventListener('connectionstatechange', this.connectionStateChangeHandler);
+ // Disconnect if data channels close unexpectedly, e.g. can happen due to message size > ~255kB (RTCPeerConnection.sctp.maxMessageSizeLimit: 262144)
+ Object.values(this.rtc.channels).forEach((datachannel) => {
+ datachannel.onclose = (e) => {
+ [...this.responseMap.values()].forEach((promise) => promise.reject(new Error('RTCDataChannel closed unexpectedly, this is most commonly caused by message size. Note: RTC Channels have a message size limit of ~255kB.')));
+ this.close();
+ if (__classPrivateFieldGet$b(this, _RTCEndpoint_disconnectListener, "f")) {
+ __classPrivateFieldGet$b(this, _RTCEndpoint_disconnectListener, "f").call(this);
+ }
+ };
+ });
+ }
+ onDisconnect(listener) {
+ if (!__classPrivateFieldGet$b(this, _RTCEndpoint_disconnectListener, "f")) {
+ __classPrivateFieldSet$9(this, _RTCEndpoint_disconnectListener, listener, "f");
+ }
+ else {
+ throw new Error('RTCEndpoint disconnectListener cannot be set twice.');
+ }
+ }
+ receive(listener) {
+ if (__classPrivateFieldGet$b(this, _RTCEndpoint_processAction, "f")) {
+ throw new Error('You have already set a listener for this RTC Endpoint.');
+ }
+ __classPrivateFieldSet$9(this, _RTCEndpoint_processAction, listener, "f");
+ }
+ get connected() {
+ return this.rtc.rtcClient.connectionState === 'connected';
+ }
+}
+endpoint.RTCEndpoint = RTCEndpoint;
+_RTCEndpoint_processAction = new WeakMap(), _RTCEndpoint_disconnectListener = new WeakMap();
+
+var __classPrivateFieldGet$a = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __classPrivateFieldSet$8 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var _RTCStrategy_processAction, _RTCStrategy_rtcEndpointMap, _RTCStrategy_connected;
+Object.defineProperty(strategy$1, "__esModule", { value: true });
+strategy$1.RTCInfo = strategy$1.RTCStrategy = void 0;
+const endpoint_1 = endpoint;
+/*
+This is used to abstract out rtc messaging from the channels implementation using RTCEndpoints.
+*/
+class RTCStrategy {
+ constructor() {
+ _RTCStrategy_processAction.set(this, null);
+ _RTCStrategy_rtcEndpointMap.set(this, new Map());
+ _RTCStrategy_connected.set(this, true);
+ this.send = async (endpointId, action, payload) => {
+ return this.getEndpointById(endpointId).send(action, payload);
+ };
+ this.close = async () => {
+ if (__classPrivateFieldGet$a(this, _RTCStrategy_connected, "f")) {
+ __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").forEach((rtcEndpoint) => rtcEndpoint.close());
+ __classPrivateFieldSet$8(this, _RTCStrategy_rtcEndpointMap, new Map(), "f");
+ }
+ __classPrivateFieldSet$8(this, _RTCStrategy_connected, false, "f");
+ };
+ }
+ onEndpointDisconnect(endpointId, listener) {
+ this.getEndpointById(endpointId).onDisconnect(listener);
+ }
+ receive(listener) {
+ if (__classPrivateFieldGet$a(this, _RTCStrategy_processAction, "f")) {
+ throw new Error('You have already set a listener for this RTC Strategy');
+ }
+ __classPrivateFieldSet$8(this, _RTCStrategy_processAction, listener, "f");
+ __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").forEach((rtcEndpoint) => rtcEndpoint.receive(__classPrivateFieldGet$a(this, _RTCStrategy_processAction, "f")));
+ }
+ getEndpointById(endpointId) {
+ const endpoint = __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").get(endpointId);
+ if (!endpoint) {
+ throw new Error(`Client with endpoint id ${endpointId} is not connected`);
+ }
+ return endpoint;
+ }
+ get connected() {
+ return __classPrivateFieldGet$a(this, _RTCStrategy_connected, "f");
+ }
+ isEndpointConnected(endpointId) {
+ return __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").has(endpointId);
+ }
+ addEndpoint(endpointId, payload) {
+ if (!__classPrivateFieldGet$a(this, _RTCStrategy_connected, "f")) {
+ console.warn('Adding endpoint to disconnected RTC Strategy');
+ return;
+ }
+ const clientStrat = new endpoint_1.RTCEndpoint(payload.rtc, payload.endpointIdentity);
+ if (__classPrivateFieldGet$a(this, _RTCStrategy_processAction, "f")) {
+ clientStrat.receive(__classPrivateFieldGet$a(this, _RTCStrategy_processAction, "f"));
+ }
+ __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").set(endpointId, clientStrat);
+ }
+ async closeEndpoint(endpointId) {
+ __classPrivateFieldGet$a(this, _RTCStrategy_rtcEndpointMap, "f").delete(endpointId);
+ }
+ isValidEndpointPayload(payload) {
+ const isObject = (x) => {
+ return typeof x === 'object' && x !== null;
+ };
+ return (isObject(payload) &&
+ isObject(payload.endpointIdentity) &&
+ isObject(payload.rtc) &&
+ typeof payload.endpointIdentity.endpointId === 'string');
+ }
+}
+strategy$1.RTCStrategy = RTCStrategy;
+_RTCStrategy_processAction = new WeakMap(), _RTCStrategy_rtcEndpointMap = new WeakMap(), _RTCStrategy_connected = new WeakMap();
+strategy$1.RTCInfo = { version: 2, minimumVersion: 0, type: 'rtc' };
+
+var iceManager = {};
+
+Object.defineProperty(iceManager, "__esModule", { value: true });
+iceManager.RTCICEManager = void 0;
+const base_1$i = base;
+/*
+Singleton that facilitates Offer and Answer exchange required for establishing RTC connections.
+*/
+class RTCICEManager extends base_1$i.EmitterBase {
+ constructor(wire) {
+ super(wire, 'channel');
+ this.ensureChannelOpened = (channel) => {
+ return new Promise((resolve, reject) => {
+ if (channel.readyState === 'open') {
+ resolve();
+ }
+ else if (channel.readyState === 'connecting') {
+ const listener = () => {
+ channel.removeEventListener('open', listener);
+ resolve();
+ };
+ channel.addEventListener('open', listener);
+ }
+ else {
+ reject(new Error('This Channel has already closed'));
+ }
+ });
+ };
+ }
+ static createDataChannelPromise(label, rtcClient) {
+ let resolver;
+ const promise = new Promise((resolve) => {
+ resolver = resolve;
+ });
+ const listener = (e) => {
+ const openListener = () => {
+ e.channel.removeEventListener('open', openListener);
+ resolver(e.channel);
+ };
+ if (e.channel.label === label) {
+ e.channel.addEventListener('open', openListener);
+ rtcClient.removeEventListener('datachannel', listener);
+ }
+ };
+ rtcClient.addEventListener('datachannel', listener);
+ return promise;
+ }
+ async listenForProviderIce(rtcConnectionId, listener) {
+ await this.on(this.createProviderEventName(rtcConnectionId), listener, { timestamp: Date.now() });
+ }
+ async raiseProviderIce(rtcConnectionId, payload) {
+ await this.wire.environment.raiseEvent(this.createRouteString(this.createProviderEventName(rtcConnectionId)), payload);
+ }
+ async listenForClientIce(rtcConnectionId, listener) {
+ await this.on(this.createClientEventName(rtcConnectionId), listener, { timestamp: Date.now() });
+ }
+ async raiseClientIce(rtcConnectionId, payload) {
+ await this.wire.environment.raiseEvent(this.createRouteString(this.createClientEventName(rtcConnectionId)), payload);
+ }
+ cleanupIceListeners(rtcConnectionId) {
+ this.removeAllListeners(this.createClientEventName(rtcConnectionId));
+ this.removeAllListeners(this.createProviderEventName(rtcConnectionId));
+ }
+ createClientEventName(rtcConnectionId) {
+ return `ice-client-${rtcConnectionId}`;
+ }
+ createProviderEventName(rtcConnectionId) {
+ return `ice-provider-${rtcConnectionId}`;
+ }
+ createRouteString(name) {
+ return `channel/${name}`;
+ }
+ createRtcPeer() {
+ return this.wire.environment.getRtcPeer();
+ }
+ async startClientOffer() {
+ // TODO replace with real guid.
+ const rtcConnectionId = Math.random().toString();
+ const rtcClient = this.createRtcPeer();
+ rtcClient.addEventListener('icecandidate', async (e) => {
+ if (e.candidate) {
+ await this.raiseClientIce(rtcConnectionId, { candidate: e.candidate?.toJSON() });
+ }
+ });
+ await this.listenForProviderIce(rtcConnectionId, async (payload) => {
+ await rtcClient.addIceCandidate(payload.candidate);
+ });
+ const channels = {
+ request: rtcClient.createDataChannel('request'),
+ response: rtcClient.createDataChannel('response')
+ };
+ const offer = await rtcClient.createOffer();
+ await rtcClient.setLocalDescription(offer);
+ const channelsOpened = Promise.all([channels.request, channels.response].map(this.ensureChannelOpened)).then(() => undefined);
+ return { rtcClient, channels, offer, rtcConnectionId, channelsOpened };
+ }
+ async finishClientOffer(rtcClient, answer, providerReady) {
+ await rtcClient.setRemoteDescription(answer);
+ await providerReady;
+ return true;
+ }
+ async createProviderAnswer(rtcConnectionId, offer) {
+ const rtcClient = this.createRtcPeer();
+ const requestChannelPromise = RTCICEManager.createDataChannelPromise('request', rtcClient);
+ const responseChannelPromise = RTCICEManager.createDataChannelPromise('response', rtcClient);
+ rtcClient.addEventListener('icecandidate', async (e) => {
+ if (e.candidate) {
+ await this.raiseProviderIce(rtcConnectionId, { candidate: e.candidate?.toJSON() });
+ }
+ });
+ await this.listenForClientIce(rtcConnectionId, async (payload) => {
+ await rtcClient.addIceCandidate(payload.candidate);
+ });
+ await rtcClient.setRemoteDescription(offer);
+ const answer = await rtcClient.createAnswer();
+ await rtcClient.setLocalDescription(answer);
+ const channels = Promise.all([requestChannelPromise, responseChannelPromise]).then(([request, response]) => {
+ // Clean up ice events.
+ this.cleanupIceListeners(rtcConnectionId);
+ return { request, response };
+ });
+ return {
+ rtcClient,
+ answer,
+ channels
+ };
+ }
+}
+iceManager.RTCICEManager = RTCICEManager;
+
+var provider = {};
+
+var runtimeVersioning = {};
+
+Object.defineProperty(runtimeVersioning, "__esModule", { value: true });
+runtimeVersioning.runtimeUuidMeetsMinimumRuntimeVersion = runtimeVersioning.parseRuntimeUuid = runtimeVersioning.meetsMinimumRuntimeVersion = void 0;
+function vNum(x) {
+ return [...x.split('.').reverse().entries()].reduce((p, [i, v]) => p + +v * 10000 ** i, 0);
+}
+/*
+ Compares runtime versions to see if the current runtime meets your desired minimum.
+*/
+function meetsMinimumRuntimeVersion(currentVersion, minVersion) {
+ const currentVersionParsed = vNum(currentVersion);
+ const minVersionParsed = vNum(minVersion);
+ return currentVersionParsed >= minVersionParsed;
+}
+runtimeVersioning.meetsMinimumRuntimeVersion = meetsMinimumRuntimeVersion;
+// Strips the port info from the runtimeUuid, leaving just the runtime version.
+function parseRuntimeUuid(runtimeUuid) {
+ return runtimeUuid.split('/')[0];
+}
+runtimeVersioning.parseRuntimeUuid = parseRuntimeUuid;
+function runtimeUuidMeetsMinimumRuntimeVersion(runtimeUuid, minVersion) {
+ const runtimeVersion = parseRuntimeUuid(runtimeUuid);
+ return meetsMinimumRuntimeVersion(runtimeVersion, minVersion);
+}
+runtimeVersioning.runtimeUuidMeetsMinimumRuntimeVersion = runtimeUuidMeetsMinimumRuntimeVersion;
+
+var __classPrivateFieldGet$9 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __classPrivateFieldSet$7 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var _ChannelProvider_connections, _ChannelProvider_protectedObj, _ChannelProvider_strategy, _ChannelProvider_removeEndpoint, _ChannelProvider_close;
+Object.defineProperty(provider, "__esModule", { value: true });
+provider.ChannelProvider = void 0;
+const channel_1 = channel;
+const runtimeVersioning_1 = runtimeVersioning;
+/**
+ * Instance created to enable use of a channel as a provider. Allows for communication with the {@link ChannelClient ChannelClients} by invoking an action on
+ * a single client via {@link ChannelProvider#dispatch dispatch} or all clients via {@link ChannelProvider#publish publish}
+ * and to listen for communication from clients by registering an action via {@link ChannelProvider#register register}.
+ *
+ * ### Synchronous Methods:
+ * * {@link ChannelProvider#onConnection onConnection(listener)}
+ * * {@link ChannelProvider#onDisconnection onDisconnection(listener)}
+ * * {@link ChannelProvider#publish publish(action, payload)}
+ * * {@link ChannelProvider#register register(action, listener)}
+ * * {@link ChannelProvider#remove remove(action)}
+ *
+ * ### Asynchronous Methods:
+ * * {@link ChannelProvider#destroy destroy()}
+ * * {@link ChannelProvider#dispatch dispatch(to, action, payload)}
+ * * {@link ChannelProvider#getAllClientInfo getAllClientInfo()}
+ *
+ * ### Middleware:
+ * Middleware functions receive the following arguments: (action, payload, senderId).
+ * The return value of the middleware function will be passed on as the payload from beforeAction, to the action listener, to afterAction
+ * unless it is undefined, in which case the most recently defined payload is used. Middleware can be used for side effects.
+ * * {@link ChannelProvider#setDefaultAction setDefaultAction(middleware)}
+ * * {@link ChannelProvider#onError onError(middleware)}
+ * * {@link ChannelProvider#beforeAction beforeAction(middleware)}
+ * * {@link ChannelProvider#afterAction afterAction(middleware)}
+ */
+class ChannelProvider extends channel_1.ChannelBase {
+ /**
+ * a read-only array containing all the identities of connecting clients.
+ */
+ get connections() {
+ return [...__classPrivateFieldGet$9(this, _ChannelProvider_connections, "f")];
+ }
+ static handleClientDisconnection(channel, payload) {
+ const removeById = channel.connections.find((identity) => identity.endpointId === payload.endpointId);
+ if (removeById) {
+ __classPrivateFieldGet$9(channel, _ChannelProvider_removeEndpoint, "f").call(channel, removeById);
+ }
+ else {
+ const multipleRemoves = channel.connections.filter((identity) => {
+ return identity.uuid === payload.uuid && identity.name === payload.name;
+ });
+ multipleRemoves.forEach(__classPrivateFieldGet$9(channel, _ChannelProvider_removeEndpoint, "f"));
+ }
+ channel.disconnectListener(payload);
+ }
+ static setProviderRemoval(provider, remove) {
+ ChannelProvider.removalMap.set(provider, remove);
+ }
+ /**
+ * @internal
+ */
+ constructor(providerIdentity, wire, strategy) {
+ super();
+ _ChannelProvider_connections.set(this, void 0);
+ _ChannelProvider_protectedObj.set(this, void 0);
+ _ChannelProvider_strategy.set(this, void 0);
+ _ChannelProvider_removeEndpoint.set(this, (identity) => {
+ const remainingConnections = this.connections.filter((clientIdentity) => clientIdentity.endpointId !== identity.endpointId);
+ __classPrivateFieldGet$9(this, _ChannelProvider_strategy, "f").closeEndpoint(identity.endpointId);
+ __classPrivateFieldSet$7(this, _ChannelProvider_connections, remainingConnections, "f");
+ });
+ // Must be bound.
+ this.processAction = async (action, payload, senderIdentity) => {
+ if (ChannelProvider.clientIsMultiRuntime(senderIdentity) &&
+ !(0, runtimeVersioning_1.runtimeUuidMeetsMinimumRuntimeVersion)(senderIdentity.runtimeUuid, '18.87.56.0')) {
+ this.handleMultiRuntimeLegacyClient(senderIdentity);
+ }
+ else {
+ this.checkForClientConnection(senderIdentity);
+ }
+ return super.processAction(action, payload, senderIdentity);
+ };
+ _ChannelProvider_close.set(this, () => {
+ __classPrivateFieldGet$9(this, _ChannelProvider_strategy, "f").close();
+ const remove = ChannelProvider.removalMap.get(this);
+ if (remove) {
+ remove();
+ }
+ });
+ __classPrivateFieldSet$7(this, _ChannelProvider_protectedObj, new channel_1.ProtectedItems(providerIdentity, wire), "f");
+ this.connectListener = () => undefined;
+ this.disconnectListener = () => undefined;
+ __classPrivateFieldSet$7(this, _ChannelProvider_connections, [], "f");
+ __classPrivateFieldSet$7(this, _ChannelProvider_strategy, strategy, "f");
+ strategy.receive(this.processAction);
+ }
+ /**
+ * Dispatch an action to a specified client. Returns a promise for the result of executing that action on the client side.
+ *
+ * @param to - Identity of the target client.
+ * @param action - Name of the action to be invoked by the client.
+ * @param payload - Payload to be sent along with the action.
+ *
+ * @remarks
+ *
+ * Because multiple clients can share the same `name` and `uuid`, when dispatching from a provider to a client,
+ * the `identity` you provide must include the client's unique `endpointId` property. This `endpointId` is
+ * passed to the provider in both the `Provider.onConnection` callback and in any registered action callbacks.
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.register('provider-action', async (payload, identity) => {
+ * console.log(payload, identity);
+ * return await provider.dispatch(identity, 'client-action', 'Hello, World!');
+ * });
+ * })();
+ * ```
+ */
+ dispatch(to, action, payload) {
+ const endpointId = to.endpointId ?? this.getEndpointIdForOpenFinId(to, action);
+ if (endpointId && __classPrivateFieldGet$9(this, _ChannelProvider_strategy, "f").isEndpointConnected(endpointId)) {
+ return __classPrivateFieldGet$9(this, _ChannelProvider_strategy, "f").send(endpointId, action, payload);
+ }
+ return Promise.reject(new Error(`Client connection with identity uuid: ${to.uuid} / name: ${to.name} / endpointId: ${endpointId} no longer connected.`));
+ }
+ async processConnection(senderId, payload) {
+ __classPrivateFieldGet$9(this, _ChannelProvider_connections, "f").push(senderId);
+ return this.connectListener(senderId, payload);
+ }
+ /**
+ * Publish an action and payload to every connected client.
+ * Synchronously returns an array of promises for each action (see dispatch).
+ *
+ * @param action
+ * @param payload
+ *
+ * @example
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.register('provider-action', async (payload, identity) => {
+ * console.log(payload, identity);
+ * return await Promise.all(provider.publish('client-action', { message: 'Broadcast from provider'}));
+ * });
+ * })();
+ * ```
+ */
+ publish(action, payload) {
+ return this.connections.map((to) => __classPrivateFieldGet$9(this, _ChannelProvider_strategy, "f").send(to.endpointId, action, payload));
+ }
+ /**
+ * Register a listener that is called on every new client connection.
+ *
+ * @remarks It is passed the identity of the connecting client and a payload if it was provided to Channel.connect.
+ * If you wish to reject the connection, throw an error. Be sure to synchronously provide an onConnection upon receipt of
+ * the channelProvider to ensure all potential client connections are caught by the listener.
+ *
+ * Because multiple clients can exist at the same `name` and `uuid`, in order to distinguish between individual clients,
+ * the `identity` argument in a provider's `onConnection` callback contains an `endpointId` property. When dispatching from a
+ * provider to a client, the `endpointId` property must be provided in order to send an action to a specific client.
+ *
+ * @example
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * provider.onConnection(identity => {
+ * console.log('Client connected', identity);
+ * });
+ * })();
+ * ```
+ *
+ * Reject connection:
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * provider.onConnection(identity => {
+ * throw new Error('Connection Rejected');
+ * });
+ * })();
+ * ```
+ * @param listener
+ */
+ onConnection(listener) {
+ this.connectListener = listener;
+ }
+ /**
+ * Register a listener that is called on client disconnection. It is passed the disconnection event of the disconnecting
+ * client.
+ *
+ * @param listener
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.onDisconnection(evt => {
+ * console.log('Client disconnected', `uuid: ${evt.uuid}, name: ${evt.name}`);
+ * });
+ * })();
+ * ```
+ */
+ onDisconnection(listener) {
+ this.disconnectListener = listener;
+ }
+ /**
+ * Destroy the channel, raises `disconnected` events on all connected channel clients.
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * const provider = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * await provider.destroy();
+ * })();
+ * ```
+ */
+ async destroy() {
+ const protectedObj = __classPrivateFieldGet$9(this, _ChannelProvider_protectedObj, "f");
+ const { channelName } = protectedObj.providerIdentity;
+ __classPrivateFieldSet$7(this, _ChannelProvider_connections, [], "f");
+ await protectedObj.wire.sendAction('destroy-channel', { channelName });
+ __classPrivateFieldGet$9(this, _ChannelProvider_close, "f").call(this);
+ }
+ /**
+ * Returns an array with info on every Client connected to the Provider
+ *
+ * @example
+ *
+ * ```js
+ * const provider = await fin.InterApplicationBus.Channel.create('openfin');
+ * const client = await fin.InterApplicationBus.Channel.connect('openfin');
+ * const clientInfo = await provider.getAllClientInfo();
+ *
+ * console.log(clientInfo);
+ *
+ * // [
+ * // {
+ * // "uuid": "openfin",
+ * // "name": "openfin-view",
+ * // "endpointId": "6d4c7ca8-4a74-4634-87f8-760558229613",
+ * // "entityType": "view",
+ * // "url": "https://openfin.co"
+ * // },
+ * // {
+ * // "uuid": "openfin2",
+ * // "name": "openfin-view2",
+ * // "endpointId": "4z5d8ab9-2b81-3691-91ex-142179382511",
+ * // "entityType": "view",
+ * // "url": "https://example.com"
+ * // }
+ * //]
+ * ```
+ */
+ async getAllClientInfo() {
+ return this.connections.map((clientInfo) => {
+ const { uuid, name, endpointId, entityType, connectionUrl } = clientInfo;
+ return { uuid, name, endpointId, entityType, connectionUrl };
+ });
+ }
+ checkForClientConnection(clientIdentity) {
+ if (!this.isClientConnected(clientIdentity)) {
+ throw new Error(`This action was sent from a client that is not connected to the provider.
+ Client Identity: {uuid: ${clientIdentity.uuid}, name: ${clientIdentity.name}, endpointId: ${clientIdentity.endpointId}}`);
+ }
+ }
+ isClientConnected(clientIdentity) {
+ if (ChannelProvider.clientIdentityIncludesEndpointId(clientIdentity)) {
+ return this.connections.some((identity) => {
+ return (
+ // Might be redundant to check for uuid and name here after we get an endpointId match, but just in case
+ identity.endpointId === clientIdentity.endpointId &&
+ identity.uuid === clientIdentity.uuid &&
+ identity.name === clientIdentity.name);
+ });
+ }
+ return this.isLegacyClientConnected(clientIdentity);
+ }
+ isLegacyClientConnected(clientIdentity) {
+ return this.connections.some((identity) => {
+ return identity.uuid === clientIdentity.uuid && identity.name === clientIdentity.name;
+ });
+ }
+ handleMultiRuntimeLegacyClient(senderIdentity) {
+ if (!this.isLegacyClientConnected(senderIdentity)) {
+ throw new Error(`This action was sent from a client that is not connected to the provider. Client Identity:
+ {uuid: ${senderIdentity.uuid}, name: ${senderIdentity.name}, endpointId: ${senderIdentity.endpointId}}`);
+ }
+ }
+ getEndpointIdForOpenFinId(clientIdentity, action) {
+ const matchingConnections = this.connections.filter((c) => c.name === clientIdentity.name && c.uuid === clientIdentity.uuid);
+ if (matchingConnections.length >= 2) {
+ const protectedObj = __classPrivateFieldGet$9(this, _ChannelProvider_protectedObj, "f");
+ const { uuid, name } = clientIdentity;
+ const providerUuid = protectedObj?.providerIdentity.uuid;
+ const providerName = protectedObj?.providerIdentity.name;
+ // eslint-disable-next-line no-console
+ console.warn(`WARNING: Dispatch call may have unintended results. The "to" argument of your dispatch call is missing the
+ "endpointId" parameter. The identity you are dispatching to ({uuid: ${uuid}, name: ${name}})
+ has multiple channelClients for this channel. Your dispatched action: (${action}) from the provider:
+ ({uuid: ${providerUuid}, name: ${providerName}}) will only be processed by the most recently-created client.`);
+ }
+ // Pop to return the most recently created endpointId.
+ return matchingConnections.pop()?.endpointId;
+ }
+ // eslint-disable-next-line class-methods-use-this
+ static clientIdentityIncludesEndpointId(subscriptionIdentity) {
+ return subscriptionIdentity.endpointId !== undefined;
+ }
+ // eslint-disable-next-line class-methods-use-this
+ static clientIsMultiRuntime(subscriptionIdentity) {
+ return subscriptionIdentity.runtimeUuid !== undefined;
+ }
+}
+provider.ChannelProvider = ChannelProvider;
+_ChannelProvider_connections = new WeakMap(), _ChannelProvider_protectedObj = new WeakMap(), _ChannelProvider_strategy = new WeakMap(), _ChannelProvider_removeEndpoint = new WeakMap(), _ChannelProvider_close = new WeakMap();
+// The following line should be changed following a typescript update.
+// static #removalMap = new WeakMap();
+ChannelProvider.removalMap = new WeakMap();
+
+var messageReceiver = {};
+
+Object.defineProperty(messageReceiver, "__esModule", { value: true });
+messageReceiver.MessageReceiver = void 0;
+const client_1$1 = client;
+const base_1$h = base;
+/*
+This is a singleton (per fin object) tasked with routing messages coming off the ipc to the correct endpoint.
+It needs to be a singleton because there can only be one per wire. It tracks both clients and providers' processAction passed in via the strategy.
+If functionality is not about receiving messages, it does not belong here.
+*/
+class MessageReceiver extends base_1$h.Base {
+ constructor(wire) {
+ super(wire);
+ this.onmessage = (msg) => {
+ if (msg.action === 'process-channel-message') {
+ this.processChannelMessage(msg);
+ return true;
+ }
+ return false;
+ };
+ this.endpointMap = new Map();
+ this.latestEndpointIdByChannelId = new Map();
+ wire.registerMessageHandler(this.onmessage.bind(this));
+ }
+ async processChannelMessage(msg) {
+ const { senderIdentity, providerIdentity, action, ackToSender, payload, intendedTargetIdentity } = msg.payload;
+ const key = intendedTargetIdentity.channelId ?? // The recipient is a provider
+ intendedTargetIdentity.endpointId ?? // The recipient is a client
+ this.latestEndpointIdByChannelId.get(providerIdentity.channelId); // No endpointId was passed, make best attempt
+ const handler = this.endpointMap.get(key);
+ if (!handler) {
+ ackToSender.payload.success = false;
+ ackToSender.payload.reason = `Client connection with identity uuid: ${this.wire.me.uuid} / name: ${this.wire.me.name} / endpointId: ${key} no longer connected.`;
+ return this.wire.sendRaw(ackToSender);
+ }
+ try {
+ const res = await handler(action, payload, senderIdentity);
+ ackToSender.payload.payload = ackToSender.payload.payload || {};
+ ackToSender.payload.payload.result = res;
+ return this.wire.sendRaw(ackToSender);
+ }
+ catch (e) {
+ ackToSender.payload.success = false;
+ ackToSender.payload.reason = e.message;
+ return this.wire.sendRaw(ackToSender);
+ }
+ }
+ addEndpoint(handler, channelId, endpointId) {
+ this.endpointMap.set(endpointId, handler);
+ // Providers have the same endpointId and channelId.
+ // This is only used when clients are receiving messages from providers, so we shouldn't save provider endpointId here.
+ if (channelId !== endpointId) {
+ this.latestEndpointIdByChannelId.set(channelId, endpointId);
+ }
+ }
+ removeEndpoint(channelId, endpointId) {
+ this.endpointMap.delete(endpointId);
+ if (this.latestEndpointIdByChannelId.get(channelId) === endpointId) {
+ this.latestEndpointIdByChannelId.delete(channelId);
+ }
+ }
+ checkForPreviousClientConnection(channelId) {
+ const endpointIdFromPreviousConnection = this.latestEndpointIdByChannelId.get(channelId);
+ if (endpointIdFromPreviousConnection) {
+ // Not convinced by this way of doing things, but pushing up for now.
+ client_1$1.ChannelClient.closeChannelByEndpointId(endpointIdFromPreviousConnection);
+ // eslint-disable-next-line no-console
+ console.warn('You have created a second connection to an older provider. First connection has been removed from the clientMap');
+ // eslint-disable-next-line no-console
+ console.warn('If the provider calls publish(), you may receive multiple messages.');
+ }
+ }
+}
+messageReceiver.MessageReceiver = MessageReceiver;
+
+var protocolManager = {};
+
+Object.defineProperty(protocolManager, "__esModule", { value: true });
+protocolManager.ProtocolManager = void 0;
+/*
+This should be agnostic of any actual openfin code to be unit testable.
+Dependencies on the actual srategies should be handled in ConnectionManager
+*/
+class ProtocolManager {
+ // eslint-disable-next-line no-useless-constructor
+ constructor(ProtocolsInPreferenceOrder) {
+ this.ProtocolsInPreferenceOrder = ProtocolsInPreferenceOrder;
+ this.DefaultClientProtocols = ['classic'];
+ this.DefaultProviderProtocols = ['classic'];
+ this.getClientProtocols = (protocols) => {
+ const supported = protocols
+ ? this.ProtocolsInPreferenceOrder.filter((x) => protocols.includes(x))
+ : this.DefaultClientProtocols;
+ if (!supported.length) {
+ throw new Error(`No valid protocols were passed in. Accepted values are: ${this.ProtocolsInPreferenceOrder.join(', ')}.`);
+ }
+ return supported;
+ };
+ this.getProviderProtocols = (protocols) => {
+ const supported = protocols
+ ? this.ProtocolsInPreferenceOrder.filter((x) => protocols.includes(x))
+ : this.DefaultProviderProtocols;
+ if (!supported.length) {
+ throw new Error(`No valid protocols were passed in. Accepted values are: ${this.ProtocolsInPreferenceOrder.join(', ')}.`);
+ }
+ return supported;
+ };
+ this.getCompatibleProtocols = (providerProtocols, clientOffer) => {
+ const supported = clientOffer.supportedProtocols.filter((clientProtocol) => providerProtocols.some((providerProtocol) => providerProtocol.type === clientProtocol.type &&
+ clientProtocol.version >= providerProtocol.minimumVersion &&
+ providerProtocol.version >= (clientProtocol.minimumVersion ?? 0)));
+ return supported.slice(0, clientOffer.maxProtocols);
+ };
+ }
+}
+protocolManager.ProtocolManager = ProtocolManager;
+
+var strategy = {};
+
+Object.defineProperty(strategy, "__esModule", { value: true });
+class CombinedStrategy {
+ // Making this a static method because the constructor can't be typed.
+ // Otherwise it will error when calling addEndpoint but I'd rather the whole instance be typed as never.
+ static combine(a, b) {
+ return new CombinedStrategy(a, b);
+ }
+ // eslint-disable-next-line no-useless-constructor
+ constructor(primary, secondary) {
+ this.primary = primary;
+ this.secondary = secondary;
+ }
+ onEndpointDisconnect(endpointId, listener) {
+ this.primary.onEndpointDisconnect(endpointId, () => {
+ if (!this.secondary.isEndpointConnected(endpointId)) {
+ listener();
+ }
+ });
+ this.secondary.onEndpointDisconnect(endpointId, () => {
+ if (!this.primary.isEndpointConnected(endpointId)) {
+ listener();
+ }
+ });
+ }
+ isValidEndpointPayload(payload) {
+ return this.primary.isValidEndpointPayload(payload) || this.secondary.isValidEndpointPayload(payload);
+ }
+ async closeEndpoint(endpointId) {
+ await this.primary.closeEndpoint(endpointId);
+ await this.secondary.closeEndpoint(endpointId);
+ }
+ isEndpointConnected(endpoint) {
+ return this.primary.isEndpointConnected(endpoint) || this.secondary.isEndpointConnected(endpoint);
+ }
+ async addEndpoint(endpoint, payload) {
+ if (this.primary.isValidEndpointPayload(payload)) {
+ await this.primary.addEndpoint(endpoint, payload);
+ }
+ if (this.secondary.isValidEndpointPayload(payload)) {
+ await this.secondary.addEndpoint(endpoint, payload);
+ }
+ }
+ receive(listener) {
+ this.primary.receive(listener);
+ this.secondary.receive(listener);
+ }
+ send(endpointId, action, payload) {
+ if (this.primary.isEndpointConnected(endpointId)) {
+ return this.primary.send(endpointId, action, payload);
+ }
+ return this.secondary.send(endpointId, action, payload);
+ }
+ async close() {
+ await Promise.all([this.primary.close(), this.secondary.close()]);
+ }
+}
+strategy.default = CombinedStrategy;
+
+var __classPrivateFieldSet$6 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$8 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _ConnectionManager_messageReceiver, _ConnectionManager_rtcConnectionManager;
+Object.defineProperty(connectionManager, "__esModule", { value: true });
+connectionManager.ConnectionManager = void 0;
+const exhaustive_1 = exhaustive;
+const base_1$g = base;
+const strategy_1 = strategy$2;
+const strategy_2 = strategy$1;
+const ice_manager_1 = iceManager;
+const provider_1$1 = provider;
+const message_receiver_1 = messageReceiver;
+const protocol_manager_1 = protocolManager;
+const strategy_3 = strategy;
+class ConnectionManager extends base_1$g.Base {
+ static getProtocolOptionsFromStrings(protocols) {
+ return protocols.map((protocol) => {
+ switch (protocol) {
+ case 'rtc':
+ return strategy_2.RTCInfo;
+ case 'classic':
+ return strategy_1.ClassicInfo;
+ default:
+ return (0, exhaustive_1.exhaustiveCheck)(protocol, ['rtc', 'classic']);
+ }
+ });
+ }
+ constructor(wire) {
+ super(wire);
+ _ConnectionManager_messageReceiver.set(this, void 0);
+ _ConnectionManager_rtcConnectionManager.set(this, void 0);
+ this.removeChannelFromProviderMap = (channelId) => {
+ this.providerMap.delete(channelId);
+ };
+ this.onmessage = (msg) => {
+ if (msg.action === 'process-channel-connection') {
+ this.processChannelConnection(msg);
+ return true;
+ }
+ return false;
+ };
+ this.providerMap = new Map();
+ this.protocolManager = new protocol_manager_1.ProtocolManager(this.isNodeEnvironment() ? ['classic'] : ['rtc', 'classic']);
+ __classPrivateFieldSet$6(this, _ConnectionManager_messageReceiver, new message_receiver_1.MessageReceiver(wire), "f");
+ __classPrivateFieldSet$6(this, _ConnectionManager_rtcConnectionManager, new ice_manager_1.RTCICEManager(wire), "f");
+ wire.registerMessageHandler(this.onmessage.bind(this));
+ }
+ createProvider(options, providerIdentity) {
+ const opts = Object.assign(this.wire.environment.getDefaultChannelOptions().create, options || {});
+ const protocols = this.protocolManager.getProviderProtocols(opts?.protocols);
+ const createSingleStrategy = (stratType) => {
+ switch (stratType) {
+ case 'rtc':
+ return new strategy_2.RTCStrategy();
+ case 'classic':
+ return new strategy_1.ClassicStrategy(this.wire, __classPrivateFieldGet$8(this, _ConnectionManager_messageReceiver, "f"),
+ // Providers do not have an endpointId, use channelId as endpointId in the strategy.
+ providerIdentity.channelId, providerIdentity);
+ default:
+ return (0, exhaustive_1.exhaustiveCheck)(stratType, ['rtc', 'classic']);
+ }
+ };
+ const strategies = protocols.map(createSingleStrategy);
+ let strategy;
+ if (strategies.length === 2) {
+ const [a, b] = strategies;
+ strategy = strategy_3.default.combine(a, b);
+ }
+ else if (strategies.length === 1) {
+ [strategy] = strategies;
+ }
+ else {
+ // Should be impossible.
+ throw new Error('failed to combine strategies');
+ }
+ const channel = new provider_1$1.ChannelProvider(providerIdentity, this.wire, strategy);
+ const key = providerIdentity.channelId;
+ this.providerMap.set(key, {
+ provider: channel,
+ strategy,
+ supportedProtocols: ConnectionManager.getProtocolOptionsFromStrings(protocols)
+ });
+ provider_1$1.ChannelProvider.setProviderRemoval(channel, this.removeChannelFromProviderMap.bind(this));
+ return channel;
+ }
+ async createClientOffer(options) {
+ const protocols = this.protocolManager.getClientProtocols(options?.protocols);
+ let rtcPacket;
+ const supportedProtocols = await Promise.all(protocols.map(async (type) => {
+ switch (type) {
+ case 'rtc': {
+ const { rtcClient, channels, offer, rtcConnectionId, channelsOpened } = await __classPrivateFieldGet$8(this, _ConnectionManager_rtcConnectionManager, "f").startClientOffer();
+ rtcPacket = { rtcClient, channels, channelsOpened };
+ return {
+ type: 'rtc',
+ version: strategy_2.RTCInfo.version,
+ payload: { offer, rtcConnectionId }
+ };
+ }
+ case 'classic':
+ return { type: 'classic', version: strategy_1.ClassicInfo.version };
+ default:
+ return (0, exhaustive_1.exhaustiveCheck)(type, ['rtc', 'classic']);
+ }
+ }));
+ return {
+ offer: {
+ supportedProtocols,
+ maxProtocols: 2
+ },
+ rtc: rtcPacket
+ };
+ }
+ async createClientStrategy(rtcPacket, routingInfo) {
+ if (!routingInfo.endpointId) {
+ routingInfo.endpointId = this.wire.environment.getNextMessageId();
+ // For New Clients connecting to Old Providers. To prevent multi-dispatching and publishing, we delete previously-connected
+ // clients that are in the same context as the newly-connected client.
+ __classPrivateFieldGet$8(this, _ConnectionManager_messageReceiver, "f").checkForPreviousClientConnection(routingInfo.channelId);
+ }
+ const answer = routingInfo.answer ?? {
+ supportedProtocols: [{ type: 'classic', version: 1 }]
+ };
+ const createStrategyFromAnswer = async (protocol) => {
+ if (protocol.type === 'rtc' && rtcPacket) {
+ await __classPrivateFieldGet$8(this, _ConnectionManager_rtcConnectionManager, "f").finishClientOffer(rtcPacket.rtcClient, protocol.payload.answer, rtcPacket.channelsOpened);
+ return new strategy_2.RTCStrategy();
+ }
+ if (protocol.type === 'classic') {
+ return new strategy_1.ClassicStrategy(this.wire, __classPrivateFieldGet$8(this, _ConnectionManager_messageReceiver, "f"), routingInfo.endpointId, routingInfo);
+ }
+ return null;
+ };
+ const allProtocols = (await Promise.all(answer.supportedProtocols.map(createStrategyFromAnswer))).filter((x) => x !== null);
+ // Clean up logic if provider didn't support rtc.
+ if (rtcPacket && !allProtocols.some((x) => x instanceof strategy_2.RTCStrategy)) {
+ if (rtcPacket) {
+ rtcPacket.rtcClient.close();
+ }
+ }
+ let strategy;
+ if (allProtocols.length >= 2) {
+ strategy = strategy_3.default.combine(allProtocols[0], allProtocols[1]);
+ }
+ else if (allProtocols.length) {
+ [strategy] = allProtocols;
+ }
+ else {
+ // Should be impossible.
+ throw new Error('No compatible protocols');
+ }
+ // as casting rtcPacket because we won't have an rtcStrategy if rtcPacket is undefined;
+ const endpointPayload = { endpointIdentity: routingInfo, rtc: rtcPacket };
+ strategy.addEndpoint(routingInfo.channelId, endpointPayload);
+ return strategy;
+ }
+ async processChannelConnection(msg) {
+ const { clientIdentity, providerIdentity, ackToSender, payload, offer: clientOffer } = msg.payload;
+ if (!clientIdentity.endpointId) {
+ // Should be polyfilled by core but not in cases of node connecting to an old runtime.
+ clientIdentity.endpointId = this.wire.environment.getNextMessageId();
+ clientIdentity.isLocalEndpointId = true;
+ }
+ else {
+ clientIdentity.isLocalEndpointId = false;
+ }
+ const key = providerIdentity.channelId;
+ const bus = this.providerMap.get(key);
+ if (!bus) {
+ ackToSender.payload.success = false;
+ ackToSender.payload.reason = `Channel "${providerIdentity.channelName}" has been destroyed.`;
+ return this.wire.sendRaw(ackToSender);
+ }
+ const { provider, strategy, supportedProtocols } = bus;
+ try {
+ if (!(provider instanceof provider_1$1.ChannelProvider)) {
+ throw Error('Cannot connect to a channel client');
+ }
+ const offer = clientOffer ?? {
+ supportedProtocols: [{ type: 'classic', version: 1 }],
+ maxProtocols: 1
+ };
+ const overlappingProtocols = this.protocolManager.getCompatibleProtocols(supportedProtocols, offer);
+ if (!overlappingProtocols.length) {
+ throw new Error('This provider does not support any of the offered protocols.');
+ }
+ const res = await provider.processConnection(clientIdentity, payload);
+ ackToSender.payload.payload = ackToSender.payload.payload || {};
+ // Loop through all supported protocols and accumulate them into the answer
+ // addEndpoint is tricky but we need to wait for channel resolution before adding the endpoint.
+ let clientAnswer = {
+ supportedProtocols: [],
+ endpointPayloadPromise: Promise.resolve({ endpointIdentity: clientIdentity })
+ };
+ clientAnswer = await overlappingProtocols.reduce(async (accumP, protocolToUse) => {
+ const answer = await accumP;
+ if (protocolToUse.type === 'rtc') {
+ const { answer: rtcAnswer, rtcClient, channels } = await __classPrivateFieldGet$8(this, _ConnectionManager_rtcConnectionManager, "f").createProviderAnswer(protocolToUse.payload.rtcConnectionId, protocolToUse.payload.offer);
+ answer.supportedProtocols.push({
+ type: 'rtc',
+ version: strategy_2.RTCInfo.version,
+ payload: {
+ answer: rtcAnswer
+ }
+ });
+ answer.endpointPayloadPromise = answer.endpointPayloadPromise.then((endpointPayload) => channels.then((resolvedChannels) => {
+ return {
+ ...endpointPayload,
+ rtc: {
+ rtcClient,
+ channels: resolvedChannels
+ }
+ };
+ }));
+ }
+ else {
+ answer.supportedProtocols.push({ type: 'classic', version: strategy_1.ClassicInfo.version });
+ }
+ return answer;
+ }, Promise.resolve(clientAnswer));
+ // Need to as cast here.
+ clientAnswer.endpointPayloadPromise.then((endpointPayload) => strategy.addEndpoint(clientIdentity.endpointId, endpointPayload));
+ ackToSender.payload.payload.result = res;
+ ackToSender.payload.payload.answer = clientAnswer;
+ return this.wire.sendRaw(ackToSender);
+ }
+ catch (e) {
+ ackToSender.payload.success = false;
+ ackToSender.payload.reason = e.message;
+ return this.wire.sendRaw(ackToSender);
+ }
+ }
+}
+connectionManager.ConnectionManager = ConnectionManager;
+_ConnectionManager_messageReceiver = new WeakMap(), _ConnectionManager_rtcConnectionManager = new WeakMap();
+
+/**
+ * Entry points for the `Channel` subset of the `InterApplicationBus` API (`fin.InterApplicationBus.Channel`).
+ *
+ * * {@link Channel} contains static members of the `Channel` API, accessible through `fin.InterApplicationBus.Channel`.
+ * * {@link OpenFin.ChannelClient} describes a client of a channel, e.g. as returned by `fin.InterApplicationBus.Channel.connect`.
+ * * {@link OpenFin.ChannelProvider} describes a provider of a channel, e.g. as returned by `fin.InterApplicationBus.Channel.create`.
+ *
+ * @packageDocumentation
+ */
+var __classPrivateFieldSet$5 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$7 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _Channel_connectionManager, _Channel_internalEmitter, _Channel_readyToConnect;
+Object.defineProperty(channel$1, "__esModule", { value: true });
+channel$1.Channel = void 0;
+/* eslint-disable no-console */
+const events_1$5 = require$$0;
+const lazy_1$1 = lazy;
+const base_1$f = base;
+const client_1 = client;
+const connection_manager_1 = connectionManager;
+const provider_1 = provider;
+function retryDelay(count) {
+ const interval = 500; // base delay
+ const steps = 10; // How many retries to do before incrementing the delay
+ const base = 2; // How much to multiply the previous delay by
+ const max = 30000; // max delay
+ const step = Math.floor(count / steps);
+ const delay = Math.min(max, interval * base ** step);
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(false);
+ }, delay);
+ });
+}
+/**
+ * The Channel API allows an OpenFin application to create a channel as a {@link ChannelProvider ChannelProvider},
+ * or connect to a channel as a {@link ChannelClient ChannelClient}.
+ * @remarks The "handshake" between the communication partners is
+ * simplified when using a channel. A request to connect to a channel as a client will return a promise that resolves if/when the channel has been created. Both the
+ * provider and client can dispatch actions that have been registered on their opposites, and dispatch returns a promise that resolves with a payload from the other
+ * communication participant. There can be only one provider per channel, but many clients. Version `9.61.35.*` or later is required for both communication partners.
+ *
+ * Asynchronous Methods:
+ * * {@link Channel.create create(channelName, options)}
+ * * {@link Channel.connect connect(channelName, options)}
+ * * {@link Channel.onChannelConnect onChannelConnect(listener)}
+ * * {@link Channel.onChannelDisconnect onChannelDisconnect(listener)}
+ */
+class Channel extends base_1$f.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ super(wire, 'channel');
+ _Channel_connectionManager.set(this, void 0);
+ _Channel_internalEmitter.set(this, new events_1$5.EventEmitter());
+ // OpenFin API has not been injected at construction time, *must* wait for API to be ready.
+ _Channel_readyToConnect.set(this, new lazy_1$1.AsyncRetryableLazy(async () => {
+ await Promise.all([
+ this.on('disconnected', (eventPayload) => {
+ client_1.ChannelClient.handleProviderDisconnect(eventPayload);
+ }),
+ this.on('connected', (...args) => {
+ __classPrivateFieldGet$7(this, _Channel_internalEmitter, "f").emit('connected', ...args);
+ })
+ ]).catch(() => new Error('error setting up channel connection listeners'));
+ }));
+ __classPrivateFieldSet$5(this, _Channel_connectionManager, new connection_manager_1.ConnectionManager(wire), "f");
+ }
+ /**
+ *
+ * @internal
+ */
+ async getAllChannels() {
+ return this.wire.sendAction('get-all-channels').then(({ payload }) => payload.data);
+ }
+ /**
+ * Listens for channel connections.
+ *
+ * @param listener - callback to execute.
+ *
+ * @example
+ *
+ * ```js
+ * const listener = (channelPayload) => console.log(channelPayload); // see return value below
+ *
+ * fin.InterApplicationBus.Channel.onChannelConnect(listener);
+ *
+ * // example shape
+ * {
+ * "topic": "channel",
+ * "type": "connected",
+ * "uuid": "OpenfinPOC",
+ * "name": "OpenfinPOC",
+ * "channelName": "counter",
+ * "channelId": "OpenfinPOC/OpenfinPOC/counter"
+ * }
+ *
+ * ```
+ */
+ async onChannelConnect(listener) {
+ await this.on('connected', listener);
+ }
+ /**
+ * Listen for channel disconnections.
+ *
+ * @param listener - callback to execute.
+ *
+ * @example
+ *
+ * ```js
+ * const listener = (channelPayload) => console.log(channelPayload); // see return value below
+ *
+ * fin.InterApplicationBus.Channel.onChannelDisconnect(listener);
+ *
+ * // example shape
+ * {
+ * "topic": "channel",
+ * "type": "disconnected",
+ * "uuid": "OpenfinPOC",
+ * "name": "OpenfinPOC",
+ * "channelName": "counter",
+ * "channelId": "OpenfinPOC/OpenfinPOC/counter"
+ * }
+ *
+ * ```
+ */
+ async onChannelDisconnect(listener) {
+ await this.on('disconnected', listener);
+ }
+ async safeConnect(channelName, shouldWait, connectPayload) {
+ const retryInfo = { count: 0 };
+ /* eslint-disable no-await-in-loop, no-constant-condition */
+ do {
+ // setup a listener and a connected promise to await in case we connect before the channel is ready
+ let connectedListener = () => undefined;
+ const connectedPromise = new Promise((resolve) => {
+ connectedListener = (payload) => {
+ if (channelName === payload.channelName) {
+ resolve(true);
+ }
+ };
+ __classPrivateFieldGet$7(this, _Channel_internalEmitter, "f").on('connected', connectedListener);
+ });
+ try {
+ if (retryInfo.count > 0) {
+ // Wait before retrying
+ // Delay returns false connectedPromise returns true so we can know if a retry is due to connected event
+ retryInfo.gotConnectedEvent = await Promise.race([retryDelay(retryInfo.count), connectedPromise]);
+ const result = await this.wire.sendAction('connect-to-channel', { ...connectPayload, retryInfo });
+ // log only if there was a retry
+ console.log(`Successfully connected to channelName: ${channelName}`);
+ return result.payload.data;
+ }
+ // Send retryInfo to the core for debug log inclusion
+ const sentMessagePromise = this.wire.sendAction('connect-to-channel', connectPayload);
+ // Save messageId from the first connection attempt
+ retryInfo.originalMessageId = sentMessagePromise.messageId;
+ const result = await sentMessagePromise;
+ return result.payload.data;
+ }
+ catch (error) {
+ if (!error.message.includes('internal-nack')) {
+ // Not an internal nack, break the loop
+ throw error;
+ }
+ if (shouldWait && retryInfo.count === 0) {
+ // start waiting on the next iteration, warn the user
+ console.warn(`No channel found for channelName: ${channelName}. Waiting for connection...`);
+ }
+ }
+ finally {
+ retryInfo.count += 1;
+ // in case of other errors, remove our listener
+ __classPrivateFieldGet$7(this, _Channel_internalEmitter, "f").removeListener('connected', connectedListener);
+ }
+ } while (shouldWait); // If we're waiting we retry the above loop
+ // Should wait was false, no channel was found.
+ throw new Error(`No channel found for channelName: ${channelName}.`);
+ /* eslint-enable no-await-in-loop, no-constant-condition */
+ }
+ /**
+ * Connect to a channel. If you wish to send a payload to the provider, add a payload property to the options argument.
+ * EXPERIMENTAL: pass { protocols: ['rtc'] } as options to opt-in to High Throughput Channels.
+ *
+ * @param channelName - Name of the target channel.
+ * @param options - Connection options.
+ * @returns Returns a promise that resolves with an instance of {@link ChannelClient ChannelClient}.
+ *
+ * @remarks The connection request will be routed to the channelProvider if/when the channel is created. If the connect
+ * request is sent prior to creation, the promise will not resolve or reject until the channel is created by a channelProvider
+ * (whether or not to wait for creation is configurable in the connectOptions).
+ *
+ * The connect call returns a promise that will resolve with a channelClient bus if accepted by the channelProvider, or reject if
+ * the channelProvider throws an error to reject the connection. This bus can communicate with the Provider, but not to other
+ * clients on the channel. Using the bus, the channelClient can register actions and middleware. Channel lifecycle can also be
+ * handled with an onDisconnection listener.
+ *
+ * @example
+ *
+ * ```js
+ * async function makeClient(channelName) {
+ * // A payload can be sent along with channel connection requests to help with authentication
+ * const connectPayload = { payload: 'token' };
+ *
+ * // If the channel has been created this request will be sent to the provider. If not, the
+ * // promise will not be resolved or rejected until the channel has been created.
+ * const clientBus = await fin.InterApplicationBus.Channel.connect(channelName, connectPayload);
+ *
+ * clientBus.onDisconnection(channelInfo => {
+ * // handle the channel lifecycle here - we can connect again which will return a promise
+ * // that will resolve if/when the channel is re-created.
+ * makeClient(channelInfo.channelName);
+ * })
+ *
+ * clientBus.register('topic', (payload, identity) => {
+ * // register a callback for a topic to which the channel provider can dispatch an action
+ * console.log('Action dispatched by provider: ', JSON.stringify(identity));
+ * console.log('Payload sent in dispatch: ', JSON.stringify(payload));
+ * return {
+ * echo: payload
+ * };
+ * });
+ * }
+ *
+ * makeClient('channelName')
+ * .then(() => console.log('Connected'))
+ * .catch(console.error);
+ * ```
+ */
+ async connect(channelName, options = {}) {
+ // Make sure we don't connect before listeners are set up
+ // This also errors if we're not in OpenFin, ensuring we don't run unnecessary code
+ await __classPrivateFieldGet$7(this, _Channel_readyToConnect, "f").getValue();
+ if (!channelName || typeof channelName !== 'string') {
+ throw new Error('Please provide a channelName string to connect to a channel.');
+ }
+ const opts = { wait: true, ...this.wire.environment.getDefaultChannelOptions().connect, ...options };
+ const { offer, rtc: rtcPacket } = await __classPrivateFieldGet$7(this, _Channel_connectionManager, "f").createClientOffer(opts);
+ let connectionUrl;
+ if (this.fin.me.isFrame || this.fin.me.isView || this.fin.me.isWindow) {
+ connectionUrl = (await this.fin.me.getInfo()).url;
+ }
+ const connectPayload = {
+ channelName,
+ ...opts,
+ offer,
+ connectionUrl
+ };
+ const routingInfo = await this.safeConnect(channelName, opts.wait, connectPayload);
+ const strategy = await __classPrivateFieldGet$7(this, _Channel_connectionManager, "f").createClientStrategy(rtcPacket, routingInfo);
+ const channel = new client_1.ChannelClient(routingInfo, this.wire, strategy);
+ // It is the client's responsibility to handle endpoint disconnection to the provider.
+ // If the endpoint dies, the client will force a disconnection through the core.
+ // The provider does not care about endpoint disconnection.
+ strategy.onEndpointDisconnect(routingInfo.channelId, async () => {
+ try {
+ await channel.sendDisconnectAction();
+ }
+ catch (error) {
+ console.warn(`Something went wrong during disconnect for client with uuid: ${routingInfo.uuid} / name: ${routingInfo.name} / endpointId: ${routingInfo.endpointId}.`);
+ }
+ finally {
+ client_1.ChannelClient.handleProviderDisconnect(routingInfo);
+ }
+ });
+ return channel;
+ }
+ /**
+ * Create a new channel.
+ * You must provide a unique channelName. If a channelName is not provided, or it is not unique, the creation will fail.
+ * EXPERIMENTAL: pass { protocols: ['rtc'] } as options to opt-in to High Throughput Channels.
+ *
+ * @param channelName - Name of the channel to be created.
+ * @param options - Creation options.
+ * @returns Returns a promise that resolves with an instance of {@link ChannelProvider ChannelProvider}.
+ *
+ * @remarks If successful, the create method returns a promise that resolves to an instance of the channelProvider bus. The caller
+ * then becomes the “channel provider” and can use the channelProvider bus to register actions and middleware.
+ *
+ * The caller can also set an onConnection and/or onDisconnection listener that will execute on any new channel
+ * connection/disconnection attempt from a channel client. To reject a connection, simply throw an error in the
+ * onConnection listener. The default behavior is to accept all new connections.
+ *
+ * A map of client connections is updated automatically on client connection and disconnection and saved in the
+ * [read-only] `connections` property on the channelProvider bus. The channel will exist until the provider
+ * destroys it or disconnects by closing or destroying the context (navigating or reloading). To setup a channel
+ * as a channelProvider, call `Channel.create` with a unique channel name. A map of client connections is updated
+ * automatically on client connection and disconnection.
+ *
+ * @example
+ *
+ * ```js
+ * (async ()=> {
+ * // entity creates a channel and becomes the channelProvider
+ * const providerBus = await fin.InterApplicationBus.Channel.create('channelName');
+ *
+ * providerBus.onConnection((identity, payload) => {
+ * // can reject a connection here by throwing an error
+ * console.log('Client connection request identity: ', JSON.stringify(identity));
+ * console.log('Client connection request payload: ', JSON.stringify(payload));
+ * });
+ *
+ * providerBus.register('topic', (payload, identity) => {
+ * // register a callback for a 'topic' to which clients can dispatch an action
+ * console.log('Action dispatched by client: ', JSON.stringify(identity));
+ * console.log('Payload sent in dispatch: ', JSON.stringify(payload));
+ * return {
+ * echo: payload
+ * };
+ * });
+ * })();
+ * ```
+ */
+ async create(channelName, options) {
+ if (!channelName) {
+ throw new Error('Please provide a channelName to create a channel');
+ }
+ const { payload: { data: providerIdentity } } = await this.wire.sendAction('create-channel', { channelName });
+ const channel = __classPrivateFieldGet$7(this, _Channel_connectionManager, "f").createProvider(options, providerIdentity);
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ this.on('client-disconnected', (eventPayload) => {
+ if (eventPayload.channelName === channelName) {
+ provider_1.ChannelProvider.handleClientDisconnection(channel, eventPayload);
+ }
+ });
+ return channel;
+ }
+}
+channel$1.Channel = Channel;
+_Channel_connectionManager = new WeakMap(), _Channel_internalEmitter = new WeakMap(), _Channel_readyToConnect = new WeakMap();
+
+Object.defineProperty(interappbus, "__esModule", { value: true });
+interappbus.InterAppPayload = interappbus.InterApplicationBus = void 0;
+/**
+ * Entry point for the OpenFin `InterApplicationBus` API (`fin.InterApplicationBus`).
+ *
+ * * {@link InterApplicationBus} contains static members of the `InterApplicationBus` API, accessible through `fin.InterApplicationBus`.
+ *
+ * @packageDocumentation
+ */
+const events_1$4 = require$$0;
+const base_1$e = base;
+const ref_counter_1 = refCounter;
+const index_1$2 = channel$1;
+const validate_1$3 = validate;
+/**
+ * A messaging bus that allows for pub/sub messaging between different applications.
+ *
+ */
+class InterApplicationBus extends base_1$e.Base {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ super(wire);
+ this.events = {
+ subscriberAdded: 'subscriber-added',
+ subscriberRemoved: 'subscriber-removed'
+ };
+ this.refCounter = new ref_counter_1.RefCounter();
+ this.Channel = new index_1$2.Channel(wire);
+ this.emitter = new events_1$4.EventEmitter();
+ wire.registerMessageHandler(this.onmessage.bind(this));
+ this.on = this.emitter.on.bind(this.emitter);
+ this.removeAllListeners = this.emitter.removeAllListeners.bind(this.emitter);
+ }
+ /**
+ * Publishes a message to all applications running on OpenFin Runtime that
+ * are subscribed to the specified topic.
+ * @param topic The topic on which the message is sent
+ * @param message The message to be published. Can be either a primitive
+ * data type (string, number, or boolean) or composite data type (object, array)
+ * that is composed of other primitive or composite data types
+ *
+ * @example
+ * ```js
+ * fin.InterApplicationBus.publish('topic', 'hello').then(() => console.log('Published')).catch(err => console.log(err));
+ * ```
+ */
+ publish(topic, message) {
+ return this.wire
+ .sendAction('publish-message', {
+ topic,
+ message,
+ sourceWindowName: this.me.name
+ })
+ .then(() => undefined);
+ }
+ /**
+ * Sends a message to a specific application on a specific topic.
+ * @param destination The identity of the application to which the message is sent
+ * @param topic The topic on which the message is sent
+ * @param message The message to be sent. Can be either a primitive data
+ * type (string, number, or boolean) or composite data type (object, array) that
+ * is composed of other primitive or composite data types
+ *
+ * @example
+ * ```js
+ * fin.InterApplicationBus.send(fin.me, 'topic', 'Hello there!').then(() => console.log('Message sent')).catch(err => console.log(err));
+ * ```
+ */
+ async send(destination, topic, message) {
+ const errorMsg = (0, validate_1$3.validateIdentity)(destination);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ await this.wire.sendAction('send-message', {
+ destinationUuid: destination.uuid,
+ destinationWindowName: destination.name,
+ topic,
+ message,
+ sourceWindowName: this.me.name
+ });
+ }
+ /**
+ * Subscribes to messages from the specified application on the specified topic.
+ * @param source This object is described in the Identity in the typedef
+ * @param topic The topic on which the message is sent
+ * @param listener A function that is called when a message has
+ * been received. It is passed the message, uuid and name of the sending application.
+ * The message can be either a primitive data type (string, number, or boolean) or
+ * composite data type (object, array) that is composed of other primitive or composite
+ * data types
+ *
+ * @example
+ * ```js
+ * // subscribe to a specified application
+ * fin.InterApplicationBus.subscribe(fin.me, 'topic', sub_msg => console.log(sub_msg)).then(() => console.log('Subscribed to the specified application')).catch(err => console.log(err));
+ *
+ * // subscribe to wildcard
+ * fin.InterApplicationBus.subscribe({ uuid: '*' }, 'topic', sub_msg => console.log(sub_msg)).then(() => console.log('Subscribed to *')).catch(err => console.log(err));
+ * ```
+ */
+ subscribe(source, topic, listener) {
+ const subKey = this.createSubscriptionKey(source.uuid, source.name || '*', topic);
+ const sendSubscription = () => {
+ return this.wire.sendAction('subscribe', {
+ sourceUuid: source.uuid,
+ sourceWindowName: source.name || '*',
+ topic,
+ destinationWindowName: this.me.name
+ });
+ };
+ const alreadySubscribed = () => {
+ return Promise.resolve();
+ };
+ this.emitter.on(subKey, listener);
+ return this.refCounter.actOnFirst(subKey, sendSubscription, alreadySubscribed);
+ }
+ /**
+ * Unsubscribes to messages from the specified application on the specified topic.
+ *
+ * @remarks If you are listening to all apps on a topic, (i.e you passed `{ uuid:'*' }` to the subscribe function)
+ * then you need to pass `{ uuid:'*' }` to unsubscribe as well. If you are listening to a specific application,
+ * (i.e you passed `{ uuid:'some_app' }` to the subscribe function) then you need to provide the same identifier to
+ * unsubscribe, unsubscribing to `*` on that same topic will not unhook your initial listener otherwise.
+ *
+ * @param source This object is described in the Identity in the typedef
+ * @param topic The topic on which the message is sent
+ * @param listener A callback previously registered with subscribe()
+ *
+ * @example
+ * ```js
+ * const listener = console.log;
+ *
+ * // If any application publishes a message on topic `foo`, our listener will be called.
+ * await fin.InterApplicationBus.subscribe({ uuid:'*' }, 'foo', listener)
+ *
+ * // When you want to unsubscribe, you need to specify the uuid of the app you'd like to
+ * // unsubscribe from (or `*`) and provide the same function you gave the subscribe function
+ * await fin.InterApplicationBus.unsubscribe({ uuid:'*' }, 'foo', listener)
+ * ```
+ */
+ unsubscribe(source, topic, listener) {
+ const sourceWindowName = source.name || '*';
+ const subKey = this.createSubscriptionKey(source.uuid, sourceWindowName, topic);
+ const sendUnsubscription = () => {
+ return this.wire.sendAction('unsubscribe', {
+ sourceUuid: source.uuid,
+ sourceWindowName,
+ topic,
+ destinationWindowName: this.me.name
+ });
+ };
+ const dontSendUnsubscription = () => {
+ return new Promise((r) => r).then(() => undefined);
+ };
+ this.emitter.removeListener(subKey, listener);
+ return this.refCounter.actOnLast(subKey, sendUnsubscription, dontSendUnsubscription);
+ }
+ processMessage(message) {
+ const { payload: { message: payloadMessage, sourceWindowName, sourceUuid, topic } } = message;
+ const keys = [
+ this.createSubscriptionKey(sourceUuid, sourceWindowName, topic),
+ this.createSubscriptionKey(sourceUuid, '*', topic),
+ this.createSubscriptionKey('*', '*', topic)
+ ];
+ const idOfSender = { uuid: sourceUuid, name: sourceWindowName };
+ keys.forEach((key) => {
+ this.emitter.emit(key, payloadMessage, idOfSender);
+ });
+ }
+ emitSubscriverEvent(type, message) {
+ const { payload: { targetName: name, uuid, topic } } = message;
+ const payload = { name, uuid, topic };
+ this.emitter.emit(type, payload);
+ }
+ // eslint-disable-next-line class-methods-use-this
+ createSubscriptionKey(uuid, name, topic) {
+ const n = name || '*';
+ if (!(uuid && n && topic)) {
+ throw new Error('Missing uuid, name, or topic string');
+ }
+ return createKey(uuid, n, topic);
+ }
+ onmessage(message) {
+ const { action } = message;
+ switch (action) {
+ case 'process-message':
+ this.processMessage(message);
+ break;
+ case this.events.subscriberAdded:
+ this.emitSubscriverEvent(this.events.subscriberAdded, message);
+ break;
+ case this.events.subscriberRemoved:
+ this.emitSubscriverEvent(this.events.subscriberRemoved, message);
+ break;
+ }
+ return true;
+ }
+}
+interappbus.InterApplicationBus = InterApplicationBus;
+/**
+ * @internal
+ */
+class InterAppPayload {
+}
+interappbus.InterAppPayload = InterAppPayload;
+function createKey(...toHash) {
+ return toHash
+ .map((item) => {
+ return Buffer.from(`${item}`).toString('base64');
+ })
+ .join('/');
+}
+
+var clipboard = {};
+
+/**
+ * Entry point for the OpenFin `Clipboard` API (`fin.Clipboard`).
+ *
+ * * {@link Clipboard} contains static members of the `Clipboard` API, accessible through `fin.Clipboard`.
+ *
+ * @packageDocumentation
+ */
+Object.defineProperty(clipboard, "__esModule", { value: true });
+clipboard.Clipboard = void 0;
+const base_1$d = base;
+/**
+ * @PORTED
+ * WriteRequestType interface
+ * @typedef { object } WriteRequestType
+ * @property { string } data Data to be written
+ * @property { string } [type] Clipboard Type
+ */
+/**
+ * @PORTED
+ * OpenFin.WriteAnyClipboardRequest interface
+ * @typedef { object } OpenFin.WriteAnyClipboardRequest
+ * @property { string } data Data to be written
+ * @property { OpenFin.ClipboardSelectionType } [type] Clipboard Type defaults to 'clipboard', use 'selection' for linux
+ */
+/**
+ * The Clipboard API allows reading and writing to the clipboard in multiple formats.
+ *
+ */
+class Clipboard extends base_1$d.Base {
+ /**
+ * Writes data into the clipboard as plain text
+ * @param writeObj The object for writing data into the clipboard
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.writeText({
+ * data: 'hello, world'
+ * }).then(() => console.log('Text On clipboard')).catch(err => console.log(err));
+ * ```
+ */
+ async writeText(writeObj) {
+ await this.wire.sendAction('clipboard-write-text', writeObj);
+ }
+ /**
+ * Read the content of the clipboard as plain text
+ * @param type Clipboard Type defaults to 'clipboard', use 'selection' for linux
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.readText().then(text => console.log(text)).catch(err => console.log(err));
+ * ```
+ */
+ async readText(type) {
+ // NOTE: When we start supporting linux, we could detect the OS and choose 'selection' automatically for the user
+ const { payload } = await this.wire.sendAction('clipboard-read-text', { type });
+ return payload.data;
+ }
+ /**
+ * Writes data into the clipboard as an Image
+ * @param writeRequest The object to write an image to the clipboard
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.writeImage({
+ * // raw base64 string, or dataURL of either data:image/png or data:image/jpeg type
+ * image: '...'
+ * }).then(() => console.log('Image written to clipboard')).catch(err => console.log(err));
+ * ```
+ */
+ async writeImage(writeRequest) {
+ await this.wire.sendAction('clipboard-write-image', writeRequest);
+ }
+ /**
+ * Read the content of the clipboard as a base64 string or a dataURL based on the input parameter 'format', defaults to 'dataURL'
+ * @param readRequest Clipboard Read Image request with formatting options
+ *
+ * @example
+ * ```js
+ * // see TS type: OpenFin.ImageFormatOptions
+ *
+ * const pngOrDataURLOrBmpOptions = {
+ * format: 'png', // can be: 'png' | 'dataURL' | 'bmp'
+ * };
+ *
+ * const jpgOptions = {
+ * format: 'jpg',
+ * quality: 80 // optional, if omitted defaults to 100
+ * };
+ *
+ * fin.Clipboard.readImage(pngOrDataURLOrBmpOptions)
+ * .then(image => console.log('Image read from clipboard as PNG, DataURL or BMP', image))
+ * .catch(err => console.log(err));
+ *
+ * fin.Clipboard.readImage(jpgOptions)
+ * .then(image => console.log('Image read from clipboard as JPG', image))
+ * .catch(err => console.log(err));
+ *
+ * // defaults to {format: 'dataURL'}
+ * fin.Clipboard.readImage()
+ * .then(image => console.log('Image read from clipboard as DataURL', image))
+ * .catch(err => console.log(err));
+ *
+ * ```
+ */
+ async readImage(readRequest = { format: 'dataURL' }) {
+ const { payload } = await this.wire.sendAction('clipboard-read-image', readRequest);
+ return payload.data;
+ }
+ /**
+ * Writes data into the clipboard as Html
+ * @param writeObj The object for writing data into the clipboard
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.writeHtml({
+ * data: '
Hello, World!
'
+ * }).then(() => console.log('HTML On clipboard')).catch(err => console.log(err));
+ * ```
+ */
+ async writeHtml(writeObj) {
+ await this.wire.sendAction('clipboard-write-html', writeObj);
+ }
+ /**
+ * Read the content of the clipboard as Html
+ * @param type Clipboard Type defaults to 'clipboard', use 'selection' for linux
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.readHtml().then(html => console.log(html)).catch(err => console.log(err));
+ * ```
+ */
+ async readHtml(type) {
+ const { payload } = await this.wire.sendAction('clipboard-read-html', { type });
+ return payload.data;
+ }
+ /**
+ * Writes data into the clipboard as Rtf
+ * @param writeObj The object for writing data into the clipboard
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.writeRtf({
+ * data: 'some text goes here'
+ * }).then(() => console.log('RTF On clipboard')).catch(err => console.log(err));
+ * ```
+ */
+ async writeRtf(writeObj) {
+ await this.wire.sendAction('clipboard-write-rtf', writeObj);
+ }
+ /**
+ * Read the content of the clipboard as Rtf
+ * @param type Clipboard Type defaults to 'clipboard', use 'selection' for linux
+ *
+ * @example
+ *
+ * ```js
+ * const writeObj = {
+ * data: 'some text goes here'
+ * };
+ * async function readRtf() {
+ * await fin.Clipboard.writeRtf(writeObj);
+ * return await fin.Clipboard.readRtf();
+ * }
+ * readRtf().then(rtf => console.log(rtf)).catch(err => console.log(err));
+ * ```
+ */
+ async readRtf(type) {
+ const { payload } = await this.wire.sendAction('clipboard-read-rtf', { type });
+ return payload.data;
+ }
+ /**
+ * Writes data into the clipboard
+ * @param writeObj The object for writing data into the clipboard
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.write({
+ * data: {
+ * text: 'a',
+ * html: 'b',
+ * rtf: 'c',
+ * // Can be either a base64 string, or a DataURL string. If using DataURL, the
+ * // supported formats are `data:image/png[;base64],` and `data:image/jpeg[;base64],`.
+ * // Using other image/ DataURLs will throw an Error.
+ * image: '...'
+ * }
+ * }).then(() => console.log('write data into clipboard')).catch(err => console.log(err));
+ * ```
+ */
+ async write(writeObj) {
+ await this.wire.sendAction('clipboard-write', writeObj);
+ }
+ /**
+ * Reads available formats for the clipboard type
+ * @param type Clipboard Type defaults to 'clipboard', use 'selection' for linux
+ *
+ * @example
+ * ```js
+ * fin.Clipboard.getAvailableFormats().then(formats => console.log(formats)).catch(err => console.log(err));
+ * ```
+ */
+ async getAvailableFormats(type) {
+ const { payload } = await this.wire.sendAction('clipboard-read-formats', { type });
+ return payload.data;
+ }
+}
+clipboard.Clipboard = Clipboard;
+
+var externalApplication = {};
+
+var Factory$5 = {};
+
+var Instance$4 = {};
+
+Object.defineProperty(Instance$4, "__esModule", { value: true });
+Instance$4.ExternalApplication = void 0;
+/* eslint-disable import/prefer-default-export */
+const base_1$c = base;
+/**
+ * An ExternalApplication object representing native language adapter connections to the runtime. Allows
+ * the developer to listen to {@link OpenFin.ExternalApplicationEvents external application events}.
+ * Discovery of connections is provided by {@link System.System.getAllExternalApplications getAllExternalApplications}.
+ *
+ * Processes that can be wrapped as `ExternalApplication`s include the following:
+ * - Processes which have connected to an OpenFin runtime via an adapter
+ * - Processes started via `System.launchExternalApplication`
+ * - Processes monitored via `System.monitorExternalProcess`
+ */
+class ExternalApplication extends base_1$c.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire, identity) {
+ super(wire, 'external-application', identity.uuid);
+ this.identity = identity;
+ }
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function addListener
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function on
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function once
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependListener
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * The listener is added to the beginning of the listeners array.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependOnceListener
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Remove a listener from the listener array for the specified event.
+ * Caution: Calling this method changes the array indices in the listener array behind the listener.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function removeListener
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Removes all listeners, or those of the specified event.
+ * @param eventType - The type of the event.
+ *
+ * @function removeAllListeners
+ * @memberof ExternalApplication
+ * @instance
+ * @tutorial ExternalApplication.EventEmitter
+ */
+ /**
+ * Retrieves information about the external application.
+ *
+ * @example
+ * ```js
+ * async function getInfo() {
+ * const extApp = await fin.ExternalApplication.wrap('javaApp-uuid');
+ * return await extApp.getInfo();
+ * }
+ * getInfo().then(info => console.log(info)).catch(err => console.log(err));
+ * ```
+ */
+ getInfo() {
+ return this.wire.sendAction('get-external-application-info', this.identity).then(({ payload }) => payload.data);
+ }
+}
+Instance$4.ExternalApplication = ExternalApplication;
+
+Object.defineProperty(Factory$5, "__esModule", { value: true });
+Factory$5.ExternalApplicationModule = void 0;
+const base_1$b = base;
+const Instance_1$4 = Instance$4;
+/**
+ * Static namespace for OpenFin API methods that interact with the {@link ExternalApplication} class, available under `fin.ExternalApplication`.
+ */
+class ExternalApplicationModule extends base_1$b.Base {
+ /**
+ * Asynchronously returns an External Application object that represents an external application.
+ * It is possible to wrap a process that does not yet exist, (for example, to listen for startup-related events)
+ * provided its uuid is already known.
+ * @param uuid The UUID of the external application to be wrapped
+ *
+ * @example
+ * ```js
+ * fin.ExternalApplication.wrap('javaApp-uuid');
+ * .then(extApp => console.log('wrapped external application'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ wrap(uuid) {
+ this.wire.sendAction('external-application-wrap').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return Promise.resolve(new Instance_1$4.ExternalApplication(this.wire, { uuid }));
+ }
+ /**
+ * Synchronously returns an External Application object that represents an external application.
+ * It is possible to wrap a process that does not yet exist, (for example, to listen for startup-related events)
+ * provided its uuid is already known.
+ * @param uuid The UUID of the external application to be wrapped
+ *
+ * @example
+ * ```js
+ * const extApp = fin.ExternalApplication.wrapSync('javaApp-uuid');
+ * const info = await extApp.getInfo();
+ * console.log(info);
+ * ```
+ */
+ wrapSync(uuid) {
+ this.wire.sendAction('external-application-wrap-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return new Instance_1$4.ExternalApplication(this.wire, { uuid });
+ }
+}
+Factory$5.ExternalApplicationModule = ExternalApplicationModule;
+
+(function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ /**
+ * Entry points for the OpenFin `ExternalApplication` API (`fin.ExternalApplication`).
+ *
+ * * {@link ExternalApplicationModule} contains static members of the `ExternalApplication` type, accessible through `fin.ExternalApplication`.
+ * * {@link ExternalApplication} describes an instance of an OpenFin ExternalApplication, e.g. as returned by `fin.ExternalApplication.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ */
+ __exportStar(Factory$5, exports);
+ __exportStar(Instance$4, exports);
+} (externalApplication));
+
+var frame = {};
+
+var Factory$4 = {};
+
+var Instance$3 = {};
+
+Object.defineProperty(Instance$3, "__esModule", { value: true });
+Instance$3._Frame = void 0;
+/* eslint-disable import/prefer-default-export */
+const base_1$a = base;
+/**
+ * An iframe represents an embedded HTML page within a parent HTML page. Because this embedded page
+ * has its own DOM and global JS context (which may or may not be linked to that of the parent depending
+ * on if it is considered out of the root domain or not), it represents a unique endpoint as an OpenFin
+ * connection. Iframes may be generated dynamically, or be present on initial page load and each non-CORS
+ * iframe has the OpenFin API injected by default. It is possible to opt into cross-origin iframes having
+ * the API by setting api.iframe.crossOriginInjection to true in a window's options. To block all iframes
+ * from getting the API injected you can set api.frame.sameOriginInjection
+ * to false ({@link OpenFin.WindowCreationOptions see Window Options}).
+ *
+ * To be able to directly address this context for eventing and messaging purposes, it needs a
+ * unique uuid name pairing. For OpenFin applications and windows this is provided via a configuration
+ * object in the form of a manifest URL or options object, but there is no configuration object for iframes.
+ * Just as a call to window.open outside of our Window API returns a new window with a random GUID assigned
+ * for the name, each iframe that has the API injected will be assigned a GUID as its name, the UUID will be
+ * the same as the parent window's.
+ *
+ * The fin.Frame namespace represents a way to interact with `iframes` and facilitates the discovery of current context
+ * (iframe or main window) as well as the ability to listen for {@link OpenFin.FrameEvents frame-specific events}.
+ */
+class _Frame extends base_1$a.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire, identity) {
+ super(wire, 'frame', identity.uuid, identity.name);
+ this.identity = identity;
+ }
+ /**
+ * Adds the listener function to the end of the listeners array for the specified event type.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function addListener
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - Called whenever an event of the specified type occurs.
+ * @param options - Option to support event timestamps.
+ *
+ * @function on
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function once
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Adds a listener to the beginning of the listeners array for the specified event.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependListener
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Adds a one time listener for the event. The listener is invoked only the first time the event is fired, after which it is removed.
+ * The listener is added to the beginning of the listeners array.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function prependOnceListener
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Remove a listener from the listener array for the specified event.
+ * Caution: Calling this method changes the array indices in the listener array behind the listener.
+ * @param eventType - The type of the event.
+ * @param listener - The callback function.
+ * @param options - Option to support event timestamps.
+ *
+ * @function removeListener
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Removes all listeners, or those of the specified event.
+ * @param eventType - The type of the event.
+ *
+ * @function removeAllListeners
+ * @memberof Frame
+ * @instance
+ * @tutorial Frame.EventEmitter
+ */
+ /**
+ * Returns a frame info object for the represented frame.
+ *
+ * @example
+ * ```js
+ * async function getInfo() {
+ * const frm = await fin.Frame.getCurrent();
+ * return await frm.getInfo();
+ * }
+ * getInfo().then(info => console.log(info)).catch(err => console.log(err));
+ * ```
+ */
+ getInfo() {
+ return this.wire.sendAction('get-frame-info', this.identity).then(({ payload }) => payload.data);
+ }
+ /**
+ * Returns a frame info object representing the window that the referenced iframe is
+ * currently embedded in.
+ *
+ * @example
+ * ```js
+ * async function getParentWindow() {
+ * const frm = await fin.Frame.getCurrent();
+ * return await frm.getParentWindow();
+ * }
+ * getParentWindow().then(winInfo => console.log(winInfo)).catch(err => console.log(err));
+ * ```
+ */
+ getParentWindow() {
+ return this.wire.sendAction('get-parent-window', this.identity).then(({ payload }) => payload.data);
+ }
+}
+Instance$3._Frame = _Frame;
+
+Object.defineProperty(Factory$4, "__esModule", { value: true });
+Factory$4._FrameModule = void 0;
+const base_1$9 = base;
+const validate_1$2 = validate;
+const Instance_1$3 = Instance$3;
+/**
+ * Static namespace for OpenFin API methods that interact with the {@link _Frame} class, available under `fin.Frame`.
+ */
+class _FrameModule extends base_1$9.Base {
+ /**
+ * Asynchronously returns a reference to the specified frame. The frame does not have to exist
+ * @param identity - the identity of the frame you want to wrap
+ *
+ * @example
+ * ```js
+ * fin.Frame.wrap({ uuid: 'testFrame', name: 'testFrame' })
+ * .then(frm => console.log('wrapped frame'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ async wrap(identity) {
+ this.wire.sendAction('frame-wrap').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1$2.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1$3._Frame(this.wire, identity);
+ }
+ /**
+ * Synchronously returns a reference to the specified frame. The frame does not have to exist
+ * @param identity - the identity of the frame you want to wrap
+ *
+ * @example
+ * ```js
+ * const frm = fin.Frame.wrapSync({ uuid: 'testFrame', name: 'testFrame' });
+ * const info = await frm.getInfo();
+ * console.log(info);
+ * ```
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('frame-wrap-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ const errorMsg = (0, validate_1$2.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ return new Instance_1$3._Frame(this.wire, identity);
+ }
+ /**
+ * Asynchronously returns a reference to the current frame
+ *
+ * @example
+ * ```js
+ * fin.Frame.getCurrent()
+ * .then(frm => console.log('current frame'))
+ * .catch(err => console.log(err));
+ * ```
+ */
+ getCurrent() {
+ this.wire.sendAction('frame-get-current').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return Promise.resolve(new Instance_1$3._Frame(this.wire, this.wire.environment.getCurrentEntityIdentity()));
+ }
+ /**
+ * Synchronously returns a reference to the current frame
+ *
+ * @example
+ * ```js
+ * const frm = fin.Frame.getCurrentSync();
+ * const info = await frm.getInfo();
+ * console.log(info);
+ * ```
+ */
+ getCurrentSync() {
+ this.wire.sendAction('frame-get-current-sync').catch((e) => {
+ // we do not want to expose this error, just continue if this analytics-only call fails
+ });
+ return new Instance_1$3._Frame(this.wire, this.wire.environment.getCurrentEntityIdentity());
+ }
+}
+Factory$4._FrameModule = _FrameModule;
+
+(function (exports) {
+ /**
+ * Entry points for the OpenFin `Frame` API (`fin.Frame`).
+ *
+ * * {@link _FrameModule} contains static members of the `Frame` API, accessible through `fin.Frame`.
+ * * {@link _Frame} describes an instance of an OpenFin Frame, e.g. as returned by `fin.Frame.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * Underscore prefixing of OpenFin types that alias DOM entities will be fixed in a future version.
+ *
+ * @packageDocumentation
+ */
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(Factory$4, exports);
+ __exportStar(Instance$3, exports);
+} (frame));
+
+var globalHotkey = {};
+
+Object.defineProperty(globalHotkey, "__esModule", { value: true });
+globalHotkey.GlobalHotkey = void 0;
+const base_1$8 = base;
+/**
+ * The GlobalHotkey module can register/unregister a global hotkeys.
+ *
+ */
+class GlobalHotkey extends base_1$8.EmitterBase {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ super(wire, 'global-hotkey');
+ }
+ /**
+ * Registers a global hotkey with the operating system.
+ * @param hotkey a hotkey string
+ * @param listener called when the registered hotkey is pressed by the user.
+ * @throws If the `hotkey` is reserved, see list below.
+ * @throws if the `hotkey` is already registered by another application.
+ *
+ * @remarks The `hotkey` parameter expects an electron compatible [accelerator](https://github.com/electron/electron/blob/master/docs/api/accelerator.md) and the `listener` will be called if the `hotkey` is pressed by the user.
+ * If successfull, the hotkey will be 'claimed' by the application, meaning that this register call can be called multiple times from within the same application but will fail if another application has registered the hotkey.
+ * The register call will fail if given any of these reserved Hotkeys:
+ * * `CommandOrControl+0`
+ * * `CommandOrControl+=`
+ * * `CommandOrControl+Plus`
+ * * `CommandOrControl+-`
+ * * `CommandOrControl+_`
+ * * `CommandOrControl+Shift+I`
+ * * `F5`
+ * * `CommandOrControl+R`
+ * * `Shift+F5`
+ * * `CommandOrControl+Shift+R`
+ *
+ * Raises the `registered` event.
+ *
+ * @example
+ * ```js
+ * const hotkey = 'CommandOrControl+X';
+ *
+ * fin.GlobalHotkey.register(hotkey, () => {
+ * console.log(`${hotkey} pressed`);
+ * })
+ * .then(() => {
+ * console.log('Success');
+ * })
+ * .catch(err => {
+ * console.log('Error registering the hotkey', err);
+ * });
+ * ```
+ */
+ async register(hotkey, listener) {
+ // TODO: fix typing (hotkey events are not typed)
+ // @ts-expect-error
+ await this.on(hotkey, listener);
+ await this.wire.sendAction('global-hotkey-register', { hotkey });
+ return undefined;
+ }
+ /**
+ * Unregisters a global hotkey with the operating system.
+ * @param hotkey a hotkey string
+ *
+ * @remarks This method will unregister all existing registrations of the hotkey within the application.
+ * Raises the `unregistered` event.
+ *
+ * @example
+ * ```js
+ * const hotkey = 'CommandOrControl+X';
+ *
+ * fin.GlobalHotkey.unregister(hotkey)
+ * .then(() => {
+ * console.log('Success');
+ * })
+ * .catch(err => {
+ * console.log('Error unregistering the hotkey', err);
+ * });
+ * ```
+ */
+ async unregister(hotkey) {
+ // TODO: fix typing (hotkey events are not typed)
+ // @ts-expect-error
+ await this.removeAllListeners(hotkey);
+ await this.wire.sendAction('global-hotkey-unregister', { hotkey });
+ return undefined;
+ }
+ /**
+ * Unregisters all global hotkeys for the current application.
+ *
+ * @remarks Raises the `unregistered` event for each hotkey unregistered.
+ *
+ * @example
+ * ```js
+ * fin.GlobalHotkey.unregisterAll()
+ * .then(() => {
+ * console.log('Success');
+ * })
+ * .catch(err => {
+ * console.log('Error unregistering all hotkeys for this application', err);
+ * });
+ * ```
+ */
+ async unregisterAll() {
+ await Promise.all(this.eventNames()
+ .filter((name) => !(name === 'registered' || name === 'unregistered'))
+ // TODO: fix typing (hotkey events are not typed)
+ // @ts-expect-error
+ .map((name) => this.removeAllListeners(name)));
+ await this.wire.sendAction('global-hotkey-unregister-all', {});
+ return undefined;
+ }
+ /**
+ * Checks if a given hotkey has been registered by an application within the current runtime.
+ * @param hotkey a hotkey string
+ *
+ * @example
+ * ```js
+ * const hotkey = 'CommandOrControl+X';
+ *
+ * fin.GlobalHotkey.isRegistered(hotkey)
+ * .then((registered) => {
+ * console.log(`hotkey ${hotkey} is registered ? ${registered}`);
+ * })
+ * .catch(err => {
+ * console.log('Error unregistering the hotkey', err);
+ * });
+ * ```
+ */
+ async isRegistered(hotkey) {
+ const { payload: { data } } = await this.wire.sendAction('global-hotkey-is-registered', { hotkey });
+ return data;
+ }
+}
+globalHotkey.GlobalHotkey = GlobalHotkey;
+
+var platform = {};
+
+var Factory$3 = {};
+
+var Instance$2 = {};
+
+var __classPrivateFieldGet$6 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _Platform_connectToProvider;
+Object.defineProperty(Instance$2, "__esModule", { value: true });
+Instance$2.Platform = void 0;
+/* eslint-disable import/prefer-default-export, no-undef */
+const base_1$7 = base;
+const validate_1$1 = validate;
+// Reuse clients to avoid overwriting already-registered client in provider
+const clientMap = new Map();
+/** Manages the life cycle of windows and views in the application.
+ *
+ * Enables taking snapshots of itself and applying them to restore a previous configuration
+ * as well as listen to {@link OpenFin.PlatformEvents platform events}.
+ */
+class Platform extends base_1$7.EmitterBase {
+ /**
+ * @internal
+ */
+ // eslint-disable-next-line no-shadow
+ constructor(identity, channel) {
+ // we piggyback off of application event emitter because from the core's perspective platform is just an app.
+ super(channel.wire, 'application', identity.uuid);
+ this.getClient = (identity) => {
+ this.wire.sendAction('platform-get-client', this.identity).catch((e) => {
+ // don't expose
+ });
+ const target = identity || this.identity;
+ const { uuid } = target;
+ if (!clientMap.has(uuid)) {
+ const clientPromise = __classPrivateFieldGet$6(this, _Platform_connectToProvider, "f").call(this, uuid);
+ clientMap.set(uuid, clientPromise);
+ }
+ // we set it above
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ return clientMap.get(uuid);
+ };
+ _Platform_connectToProvider.set(this, async (uuid) => {
+ try {
+ const channelName = `custom-frame-${uuid}`;
+ const client = await this._channel.connect(channelName, { wait: false });
+ client.onDisconnection(() => {
+ clientMap.delete(uuid);
+ });
+ return client;
+ }
+ catch (e) {
+ clientMap.delete(uuid);
+ throw new Error('The targeted Platform is not currently running. Listen for application-started event for the given Uuid.');
+ }
+ });
+ /**
+ * @deprecated (renamed)
+ * @ignore
+ */
+ this.launchLegacyManifest = this.launchContentManifest;
+ const errorMsg = (0, validate_1$1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ this._channel = channel;
+ this.identity = { uuid: identity.uuid };
+ this.Layout = this.fin.Platform.Layout;
+ this.Application = this.fin.Application.wrapSync(this.identity);
+ }
+ /**
+ * Creates a new view and attaches it to a specified target window.
+ * @param viewOptions View creation options
+ * @param target The window to which the new view is to be attached. If no target, create a view in a new window.
+ * @param targetView If provided, the new view will be added to the same tabstrip as targetView.
+ *
+ * @remarks If the view already exists, will reparent the view to the new target. You do not need to set a name for a View.
+ * Views that are not passed a name get a randomly generated one.
+ *
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const platform = fin.Platform.getCurrentSync();
+ *
+ * platform.createView({
+ * name: 'test_view',
+ * url: 'https://developers.openfin.co/docs/platform-api'
+ * }, windowIdentity).then(console.log);
+ * ```
+ *
+ * Reparenting a view:
+ * ```js
+ * let windowIdentity;
+ * if (fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * let platform = fin.Platform.getCurrentSync();
+ * let viewOptions = {
+ * name: 'example_view',
+ * url: 'https://example.com'
+ * };
+ * // a new view will now show in the current window
+ * await platform.createView(viewOptions, windowIdentity);
+ *
+ * const view = fin.View.wrapSync({ uuid: windowIdentity.uuid, name: 'yahoo_view' });
+ * // reparent `example_view` when a view in the new window is shown
+ * view.on('shown', async () => {
+ * let viewIdentity = { uuid: windowIdentity.uuid, name: 'example_view'};
+ * let target = {uuid: windowIdentity.uuid, name: 'test_win'};
+ * platform.createView(viewOptions, target);
+ * });
+ *
+ * // create a new window
+ * await platform.createWindow({
+ * name: "test_win",
+ * layout: {
+ * content: [
+ * {
+ * type: 'stack',
+ * content: [
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'yahoo_view',
+ * url: 'https://yahoo.com'
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * }).then(console.log);
+ * ```
+ */
+ async createView(viewOptions, target, targetView) {
+ this.wire.sendAction('platform-create-view', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ const response = await client.dispatch('create-view', {
+ target,
+ opts: viewOptions,
+ targetView
+ });
+ if (!response || (0, validate_1$1.validateIdentity)(response.identity)) {
+ throw new Error(`When overwriting the createView call, please return an object that has a valid 'identity' property: ${JSON.stringify(response)}`);
+ }
+ return this.fin.View.wrapSync(response.identity);
+ }
+ /**
+ * Creates a new Window.
+ * @param options Window creation options
+ *
+ * @remarks There are two Window types at your disposal while using OpenFin Platforms - Default Window and Custom Window.
+ *
+ * The Default Window uses the standard OpenFin Window UI. It contains the standard close, maximize and minimize buttons,
+ * and will automatically render the Window's layout if one is specified.
+ *
+ * For deeper customization, you can bring your own Window code into a Platform. This is called a Custom Window.
+ *
+ * @example
+ *
+ *
+ * The example below will create a Default Window which uses OpenFin default Window UI.
+ * The Window contains two Views in a stack Layout:
+ *
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * platform.createWindow({
+ * layout: {
+ * content: [
+ * {
+ * type: 'stack',
+ * content: [
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'test_view_1',
+ * url: 'https://cdn.openfin.co/docs/javascript/canary/Platform.html'
+ * }
+ * },
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'test_view_2',
+ * url: 'https://cdn.openfin.co/docs/javascript/canary/Platform.html'
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * }).then(console.log);
+ * ```
+ * The Default Window's design can be customized by specifying the `stylesheetUrl` property in the manifest:
+ *
+ * ```json
+ * {
+ * platform: {
+ * defaultWindowOptions: {
+ * stylesheetUrl: 'some-url.css',
+ * ...
+ * }
+ * }
+ * }
+ * ```
+ * For a list of common Layout CSS classes you can override in your custom stylesheet, see Useful Layout CSS Classes
+ **
+ * To specify a Platform Custom Window, provide a `url` property when creating a Window.
+ * If you intend to render a Layout in your Custom Window, you must also specify an `HTMLElement` that the Layout will inject into and set its `id` property to `"layout-container"`.
+ *
+ * The example below will create a Platform Custom Window:
+ *
+ * ```js
+ * // in an OpenFin app:
+ * const platform = fin.Platform.getCurrentSync();
+ * const windowConfig =
+ * {
+ * url: "https://www.my-domain.com/my-custom-window.html", // here we point to where the Custom Frame is hosted.
+ * layout: {
+ * content: [
+ * {
+ * type: "stack",
+ * content: [
+ * {
+ * type: "component",
+ * componentName: "view",
+ * componentState: {
+ * name: "app #1",
+ * url: "https://cdn.openfin.co/docs/javascript/canary/Platform.html"
+ * }
+ * },
+ * {
+ * type: "component",
+ * componentName: "view",
+ * componentState: {
+ * name: "app #2",
+ * url: "https://cdn.openfin.co/docs/javascript/canary/Platform.html"
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * };
+ * platform.createWindow(windowConfig);
+ * ```
+ *
+ * Here's an example of a minimalist Custom Platform Window implementation:
+ * ```html
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
This is a custom frame!
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ * Your Custom Window can use in-domain resources for further customization (such as CSS, scripts, etc.).
+ * For a list of common Layout CSS classes you can override in your stylesheet, see Useful Layout CSS Classes
+ *
+ * The example above will require the `body` element to have `height: 100%;` set in order to render the layout correctly.
+ */
+ async createWindow(options) {
+ this.wire.sendAction('platform-create-window', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ if (!options.reason) {
+ options.reason = 'api-call';
+ }
+ const response = await client.dispatch('create-view-container', options);
+ if (!response || (0, validate_1$1.validateIdentity)(response.identity)) {
+ throw new Error(`When overwriting the createWindow call, please return an object that has a valid 'identity' property: ${JSON.stringify(response)}`);
+ }
+ const { identity } = response;
+ const res = this.fin.Window.wrapSync(identity);
+ // we add the identity at the top level for backwards compatibility.
+ res.name = identity.name;
+ res.uuid = identity.uuid;
+ return res;
+ }
+ /**
+ * Closes current platform, all its windows, and their views.
+ *
+ * @example
+ * ```js
+ * const platform = await fin.Platform.getCurrent();
+ * platform.quit();
+ * // All windows/views in current layout platform will close and platform will shut down
+ * ```
+ */
+ async quit() {
+ this.wire.sendAction('platform-quit', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ return client.dispatch('quit');
+ }
+ /**
+ * Closes a specified view in a target window.
+ * @param viewIdentity View identity
+ *
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const viewOptions = {
+ * name: 'test_view',
+ * url: 'https://example.com'
+ * };
+ *
+ * function sleep(ms) {
+ * return new Promise(resolve => setTimeout(resolve, ms));
+ * }
+ *
+ * const platform = await fin.Platform.getCurrent();
+ *
+ * await platform.createView(viewOptions, windowIdentity);
+ * // a new view will now show in the current window
+ *
+ * await sleep(5000);
+ *
+ * const viewIdentity = { uuid: windowIdentity.uuid, name: 'test_view'};
+ * platform.closeView(viewIdentity);
+ * // the view will now close
+ * ```
+ */
+ async closeView(viewIdentity) {
+ this.wire.sendAction('platform-close-view', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ await client.dispatch('close-view', {
+ view: viewIdentity
+ });
+ }
+ /**
+ * ***DEPRECATED - please use {@link Platform.createView Platform.createView}.***
+ * Reparents a specified view in a new target window.
+ * @param viewIdentity View identity
+ * @param target new owner window identity
+ *
+ */
+ async reparentView(viewIdentity, target) {
+ // eslint-disable-next-line no-console
+ console.warn('Platform.reparentView has been deprecated, please use Platform.createView');
+ this.wire.sendAction('platform-reparent-view', this.identity).catch((e) => {
+ // don't expose
+ });
+ const normalizedViewIdentity = {
+ ...viewIdentity,
+ uuid: viewIdentity.uuid ?? this.identity.uuid
+ };
+ const view = await this.fin.View.wrap(normalizedViewIdentity);
+ const viewOptions = await view.getOptions();
+ return this.createView(viewOptions, target);
+ }
+ /**
+ * Returns a snapshot of the platform in its current state. You can pass the returning object to
+ * [Platform.applySnapshot]{@link Platform#applySnapshot} to launch it.
+ *
+ * @remarks The snapshot will include details such as an [ISO format](https://en.wikipedia.org/wiki/ISO_8601)
+ * timestamp of when the snapshot was taken, OpenFin runtime version the platform is running on, monitor information
+ * and the list of currently running windows.
+ *
+ * @example
+ * ```js
+ * const platform = await fin.Platform.getCurrent();
+ * const snapshot = await platform.getSnapshot();
+ * ```
+ */
+ async getSnapshot() {
+ this.wire.sendAction('platform-get-snapshot', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ return client.dispatch('get-snapshot');
+ }
+ /**
+ * **NOTE**: Internal use only. It is not recommended to manage the state of individual views.
+ *
+ * Returns a snapshot of a single view's options in its current state.
+ *
+ * Can be used to restore a view to a previous state.
+ *
+ * @param viewIdentity View identity
+ *
+ * @internal
+ * @experimental
+ * @remarks This slice of snapshot state is equivalent to what is stored as `componentState` for views
+ * when capturing platform state using [Platform.getSnapshot]{@link Platform#getSnapshot}.
+ *
+ * @example
+ * ```js
+ * const platform = await fin.Platform.getCurrent();
+ * const url = 'https://google.com';
+ * const view = await fin.View.create({ name: 'my-view', target: fin.me.identity, url });
+ *
+ * await view.navigate(url);
+ *
+ * const viewState = await platform.getViewSnapshot(view.identity);
+ *
+ * console.log(viewState);
+ * ```
+ */
+ async getViewSnapshot(viewIdentity) {
+ const client = await this.getClient();
+ return client.dispatch('get-view-snapshot', { viewIdentity });
+ }
+ /**
+ * Adds a snapshot to a running Platform.
+ * Requested snapshot must be a valid Snapshot object, or a url or filepath to such an object.
+ *
+ * Can optionally close existing windows and overwrite current platform state with that of a snapshot.
+ *
+ * The function accepts either a snapshot taken using {@link Platform#getSnapshot getSnapshot},
+ * or a url or filepath to a snapshot JSON object.
+ * @param requestedSnapshot Snapshot to apply, or a url or filepath.
+ * @param options Optional parameters to specify whether existing windows should be closed.
+ *
+ * @remarks Will create any windows and views that are not running but are passed in the snapshot object. Any View
+ * specified in the snapshot is assigned a randomly generated name to avoid collisions.
+ *
+ * @example
+ * ```js
+ * // Get a wrapped layout platform instance
+ * const platform = await fin.Platform.getCurrent();
+ *
+ * const snapshot = {
+ * windows: [
+ * {
+ * layout: {
+ * content: [
+ * {
+ * type: 'stack',
+ * content: [
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'component_X',
+ * url: 'https://www.openfin.co'
+ * }
+ * },
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'component_Y',
+ * url: 'https://cdn.openfin.co/embed-web/chart.html'
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * }
+ * ]
+ * }
+ *
+ * platform.applySnapshot(snapshot);
+ * ```
+ *
+ * In place of a snapshot object, `applySnapshot` can take a url or filepath and to retrieve a JSON snapshot.
+ *
+ * ```js
+ * const platform = await fin.Platform.getCurrent();
+ * platform.applySnapshot('https://api.jsonbin.io/b/5e6f903ef4331e681fc1231d/1');
+ * ```
+ *
+ * Optionally, `applySnapshot` can close existing windows and restore a Platform to a previously saved state.
+ * This is accomplished by providing `{ closeExistingWindows: true }` as an option.
+ *
+ * ```js
+ * // Get a wrapped layout platform instance
+ * const platform = await fin.Platform.getCurrent();
+ *
+ * async function addViewToWindow(winId) {
+ * return await platform.createView({
+ * name: 'test_view_3',
+ * url: 'https://openfin.co'
+ * }, winId);
+ * }
+ *
+ * async function createWindowWithTwoViews() {
+ * const platform = await fin.Platform.getCurrent();
+ *
+ * return platform.createWindow({
+ * layout: {
+ * content: [
+ * {
+ * type: 'stack',
+ * content: [
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'test_view_1',
+ * url: 'https://example.com'
+ * }
+ * },
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'test_view_2',
+ * url: 'https://yahoo.com'
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * });
+ * }
+ *
+ * const win = await createWindowWithTwoViews();
+ * // ... you will now see a new window with two views in it
+ *
+ * // we take a snapshot of the current state of the app, before changing it
+ * const snapshotOfInitialAppState = await platform.getSnapshot();
+ *
+ * // now let's change the state of the app:
+ * await addViewToWindow(win.identity);
+ * // ... the window now has three views in it
+ *
+ * await platform.applySnapshot(snapshotOfInitialAppState, { closeExistingWindows: true });
+ * // ... the window will revert to previous state, with just two views
+ *
+ * ```
+ */
+ async applySnapshot(requestedSnapshot, options) {
+ this.wire.sendAction('platform-apply-snapshot', this.identity).catch((e) => {
+ // don't expose
+ });
+ const errMsg = 'Requested snapshot must be a valid Snapshot object, or a url or filepath to such an object.';
+ let snapshot;
+ if (typeof requestedSnapshot === 'string') {
+ // Fetch and parse snapshot
+ try {
+ const response = await this._channel.wire.sendAction('get-application-manifest', {
+ manifestUrl: requestedSnapshot
+ });
+ snapshot = response.payload.data;
+ }
+ catch (err) {
+ throw new Error(`${errMsg}: ${err}`);
+ }
+ }
+ else {
+ snapshot = requestedSnapshot;
+ }
+ if (!snapshot.windows) {
+ throw new Error(errMsg);
+ }
+ const client = await this.getClient();
+ await client.dispatch('apply-snapshot', {
+ snapshot,
+ options
+ });
+ return this;
+ }
+ /**
+ * Fetches a JSON manifest using the browser process and returns a Javascript object.
+ * Can be overwritten using {@link Platform.PlatformModule.init Platform.init}.
+ * @param manifestUrl The URL of the manifest to fetch.
+ *
+ * @remarks Can be overwritten using {@link Platform#init Platform.init}.
+ *
+ * @example
+ *
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * const manifest = await platform.fetchManifest('https://www.path-to-manifest.com/app.json');
+ * console.log(manifest);
+ * ```
+ */
+ async fetchManifest(manifestUrl) {
+ const client = await this.getClient();
+ return client.dispatch('platform-fetch-manifest', { manifestUrl });
+ }
+ /**
+ * Retrieves a manifest by url and launches a legacy application manifest or snapshot into the platform. Returns a promise that
+ * resolves to the wrapped Platform.
+ * @param manifestUrl - The URL of the manifest that will be launched into the platform. If this app manifest
+ * contains a snapshot, that will be launched into the platform. If not, the application described in startup_app options
+ * will be launched into the platform. The applicable startup_app options will become {@link OpenFin.ViewCreationOptions View Options}.
+ *
+ * @remarks If the app manifest contains a snapshot, that will be launched into the platform. If not, the
+ * application described in startup_app options will be launched into the platform as a window with a single view.
+ * The applicable startup_app options will become View Options.
+ *
+ * @example
+ * ```js
+ * try {
+ * const platform = fin.Platform.getCurrentSync();
+ * await platform.launchContentManifest('http://localhost:5555/app.json');
+ * console.log(`content launched successfully into platform`);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * // For a local manifest file:
+ * try {
+ * const platform = fin.Platform.getCurrentSync();
+ * platform.launchContentManifest('file:///C:/somefolder/app.json');
+ * console.log(`content launched successfully into platform`);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * ```
+ * @experimental
+ */
+ async launchContentManifest(manifestUrl) {
+ this.wire.sendAction('platform-launch-content-manifest', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ const manifest = await this.fetchManifest(manifestUrl);
+ client.dispatch('launch-into-platform', { manifest });
+ return this;
+ }
+ /**
+ * Set the context of a host window. The context will be available to the window itself, and to its child Views. It will be saved in any platform snapshots.
+ * It can be retrieved using {@link Platform#getWindowContext getWindowContext}.
+ * @param context - A field where serializable context data can be stored to be saved in platform snapshots.
+ * @param target - A target window or view may optionally be provided. If no target is provided, the update will be applied
+ * to the current window (if called from a Window) or the current host window (if called from a View).
+ *
+ * @remarks The context data must be serializable. This can only be called from a window or view that has been launched into a
+ * platform.
+ * This method can be called from the window itself, or from any child view. Context data is shared by all
+ * entities within a window.
+ *
+ * @example
+ * Setting own context:
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * const contextData = {
+ * security: 'STOCK',
+ * currentView: 'detailed'
+ * }
+ *
+ * await platform.setWindowContext(contextData);
+ * // Context of current window is now set to `contextData`
+ * ```
+ *
+ * Setting the context of another window or view:
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * const contextData = {
+ * security: 'STOCK',
+ * currentView: 'detailed'
+ * }
+ *
+ * const windowOrViewIdentity = { uuid: fin.me.uuid, name: 'nameOfWindowOrView' };
+ * await platform.setWindowContext(contextData, windowOrViewIdentity);
+ * // Context of the target window or view is now set to `contextData`
+ * ```
+ *
+ * A view can listen to changes to its host window's context by listening to the `host-context-changed` event.
+ * This event will fire when a host window's context is updated or when the view is reparented to a new window:
+ *
+ * ```js
+ * // From a view
+ * const contextChangeHandler = ({ context }) => {
+ * console.log('Host window\'s context has changed. New context data:', context);
+ * // react to new context data here
+ * }
+ * await fin.me.on('host-context-changed', contextChangeHandler);
+ *
+ * const platform = await fin.Platform.getCurrentSync();
+ * const contextData = {
+ * security: 'STOCK',
+ * currentView: 'detailed'
+ * }
+ * platform.setWindowContext(contextData) // contextChangeHandler will log the new context
+ * ```
+ *
+ * To listen to a window's context updates, use the `context-changed` event:
+ * ```js
+ * // From a window
+ * const contextChangeHandler = ({ context }) => {
+ * console.log('This window\'s context has changed. New context data:', context);
+ * // react to new context data here
+ * }
+ * await fin.me.on('context-changed', contextChangeHandler);
+ *
+ * const platform = await fin.Platform.getCurrentSync();
+ * const contextData = {
+ * security: 'STOCK',
+ * currentView: 'detailed'
+ * }
+ * platform.setWindowContext(contextData) // contextChangeHandler will log the new context
+ * ```
+ * @experimental
+ */
+ async setWindowContext(context = {}, target) {
+ this.wire.sendAction('platform-set-window-context', this.identity).catch((e) => {
+ // don't expose
+ });
+ if (!context) {
+ throw new Error('Please provide a serializable object or string to set the context.');
+ }
+ const client = await this.getClient();
+ const { entityType } = target ? await this.fin.System.getEntityInfo(target.uuid, target.name) : this.fin.me;
+ await client.dispatch('set-window-context', {
+ context,
+ entityType,
+ target: target || { uuid: this.fin.me.uuid, name: this.fin.me.name }
+ });
+ }
+ /**
+ * Get the context context of a host window that was previously set using {@link Platform#setWindowContext setWindowContext}.
+ * The context will be saved in any platform snapshots. Returns a promise that resolves to the context.
+ * @param target - A target window or view may optionally be provided. If no target is provided, target will be
+ * the current window (if called from a Window) or the current host window (if called from a View).
+ *
+ * @remarks This method can be called from the window itself, or from any child view. Context data is shared
+ * by all entities within a window.
+ *
+ * @example
+ *
+ * Retrieving context from current window:
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * const customContext = { answer: 42 };
+ * await platform.setWindowContext(customContext);
+ *
+ * const myContext = await platform.getWindowContext();
+ * console.log(myContext); // { answer: 42 }
+ * ```
+ *
+ * Retrieving the context of another window or view:
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ *
+ * const windowOrViewIdentity = { uuid: fin.me.uuid, name: 'nameOfWindowOrView' };
+ *
+ * const targetWindowContext = await platform.getWindowContext(windowOrViewIdentity);
+ * console.log(targetWindowContext); // context of target window
+ * ```
+ * @experimental
+ */
+ async getWindowContext(target) {
+ this.wire.sendAction('platform-get-window-context', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ const { entityType } = target ? await this.fin.System.getEntityInfo(target.uuid, target.name) : this.fin.me;
+ return client.dispatch('get-window-context', {
+ target: target || { uuid: this.fin.me.uuid, name: this.fin.me.name },
+ entityType
+ });
+ }
+ /**
+ * Closes a window. If enableBeforeUnload is enabled in the Platform options, any beforeunload handler set on Views will fire
+ * This behavior can be disabled by setting skipBeforeUnload to false in the options parameter.
+ * @param winId
+ * @param options
+ *
+ * @remarks This method works by setting a `close-requested` handler on the Platform Window. If you have your own `close-requested` handler set on the Platform Window as well,
+ * it is recommended to move that logic over to the [PlatformProvider.closeWindow]{@link PlatformProvider#closeWindow} override to ensure it runs when the Window closes.
+ *
+ * @example
+ *
+ * ```js
+ * // Close the current Window inside a Window context
+ * const platform = await fin.Platform.getCurrent();
+ * platform.closeWindow(fin.me.identity);
+ *
+ * // Close the Window from inside a View context
+ * const platform = await fin.Platform.getCurrent();
+ * const parentWindow = await fin.me.getCurrentWindow();
+ * platform.closeWindow(parentWindow.identity);
+ *
+ * // Close the Window and do not fire the before unload handler on Views
+ * const platform = await fin.Platform.getCurrent();
+ * platform.closeWindow(fin.me.identity, { skipBeforeUnload: true });
+ * ```
+ * @experimental
+ */
+ async closeWindow(windowId, options = { skipBeforeUnload: false }) {
+ this.wire.sendAction('platform-close-window', this.identity).catch((e) => {
+ // don't expose
+ });
+ const client = await this.getClient();
+ return client.dispatch('close-window', { windowId, options });
+ }
+}
+Instance$2.Platform = Platform;
+_Platform_connectToProvider = new WeakMap();
+
+var layout = {};
+
+var Factory$2 = {};
+
+var Instance$1 = {};
+
+var commonUtils = {};
+
+Object.defineProperty(commonUtils, "__esModule", { value: true });
+commonUtils.overrideFromComposables = commonUtils.isValidPresetType = void 0;
+function isValidPresetType(type) {
+ switch (type) {
+ case 'columns':
+ case 'grid':
+ case 'rows':
+ case 'tabs':
+ return true;
+ default:
+ return false;
+ }
+}
+commonUtils.isValidPresetType = isValidPresetType;
+function overrideFromComposables(...overrides) {
+ return (base) => overrides.reduceRight((p, c) => (b) => c(p(b)), (x) => x)(base);
+}
+commonUtils.overrideFromComposables = overrideFromComposables;
+commonUtils.default = { isValidPresetType };
+
+var __classPrivateFieldGet$5 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _Layout_layoutClient;
+Object.defineProperty(Instance$1, "__esModule", { value: true });
+Instance$1.Layout = void 0;
+const lazy_1 = lazy;
+const validate_1 = validate;
+const base_1$6 = base;
+const common_utils_1 = commonUtils;
+const layout_entities_1 = layoutEntities;
+const layout_constants_1$1 = layout_constants;
+/**
+ *
+ * Layouts give app providers the ability to embed multiple views in a single window. The Layout namespace
+ * enables the initialization and manipulation of a window's Layout. A Layout will
+ * emit events locally on the DOM element representing the layout-container.
+ *
+ *
+ * ### Layout.DOMEvents
+ *
+ * When a Layout is created, it emits events onto the DOM element representing the Layout container.
+ * This Layout container is the DOM element referenced by containerId in {@link Layout.LayoutModule#init Layout.init}.
+ * You can use the built-in event emitter to listen to these events using [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).
+ * The events are emitted synchronously and only in the process where the Layout exists.
+ * Any values returned by the called listeners are ignored and will be discarded.
+ * If the target DOM element is destroyed, any events that have been set up on that element will be destroyed.
+ *
+ * @remarks The built-in event emitter is not an OpenFin event emitter so it doesn't share propagation semantics.
+ *
+ * #### {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener addEventListener(type, listener [, options]);}
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @example
+ * ```js
+ * const myLayoutContainer = document.getElementById('layout-container');
+ *
+ * myLayoutContainer.addEventListener('tab-created', function(event) {
+ * const { tabSelector } = event.detail;
+ * const tabElement = document.getElementById(tabSelector);
+ * const existingColor = tabElement.style.backgroundColor;
+ * tabElement.style.backgroundColor = "red";
+ * setTimeout(() => {
+ * tabElement.style.backgroundColor = existingColor;
+ * }, 2000);
+ * });
+ * ```
+ *
+ * #### {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener removeEventListener(type, listener [, options]);}
+ * Adds a listener to the end of the listeners array for the specified event.
+ * @example
+ * ```js
+ * const myLayoutContainer = document.getElementById('layout-container');
+ *
+ * const listener = function(event) {
+ * console.log(event.detail);
+ * console.log('container-created event fired once, removing listener');
+ * myLayoutContainer.removeEventListener('container-created', listener);
+ * };
+ *
+ * myLayoutContainer.addEventListener('container-created', listener);
+ * ```
+ *
+ * ### Supported event types are:
+ *
+ * * tab-created
+ * * container-created
+ * * layout-state-changed
+ * * tab-closed
+ * * tab-dropped
+ *
+ * ### Layout DOM Node Events
+ *
+ * #### tab-created
+ * Generated when a tab is created. As a user drags and drops tabs within window, new tabs are created. A single view may have multiple tabs created and destroyed during its lifetime attached to a single window.
+ * ```js
+ * // The response has the following shape in event.detail:
+ * {
+ * containerSelector: "container-component_A",
+ * name: "component_A",
+ * tabSelector: "tab-component_A",
+ * topic: "openfin-DOM-event",
+ * type: "tab-created",
+ * uuid: "OpenFin POC"
+ * }
+ * ```
+ *
+ * #### container-created
+ * Generated when a container is created. A single view will have only one container during its lifetime attached to a single window and the container's lifecycle is tied to the view. To discover when the container is destroyed, please listen to view-detached event.
+ * ```js
+ * // The response has the following shape in event.detail:
+ * {
+ * containerSelector: "container-component_A",
+ * name: "component_A",
+ * tabSelector: "tab-component_A",
+ * topic: "openfin-DOM-event",
+ * type: "container-created",
+ * uuid: "OpenFin POC"
+ * }
+ * ```
+ *
+ * ### layout-state-changed
+ * Generated when the state of the layout changes in any way, such as a view added/removed/replaced. Note that this event can fire frequently as the underlying layout can change multiple components from all kinds of changes (resizing for example). Given this, it is recommended to debounce this event and then you can use the {@link Layout#getConfig Layout.getConfig} API to retrieve the most up-to-date state.
+ * ```js
+ * // The response has the following shape in event.detail
+ * {
+ * containerSelector: "container-component_A",
+ * name: "component_A",
+ * tabSelector: "tab-component_A",
+ * topic: "openfin-DOM-event",
+ * type: "layout-state-changed",
+ * uuid: "OpenFin POC"
+ * }
+ * ```
+ *
+ * #### tab-closed
+ * Generated when a tab is closed.
+ * ```js
+ * // The response has the following shape in event.detail:
+ * {
+ * containerSelector: "container-component_A",
+ * name: "component_A",
+ * tabSelector: "tab-component_A",
+ * topic: "openfin-DOM-event",
+ * type: "tab-closed",
+ * uuid: "OpenFin POC",
+ * url: "http://openfin.co" // The url of the view that was closed.
+ * }
+ * ```
+ *
+ * #### tab-dropped
+ * Generated when a tab is dropped.
+ * ```js
+ * // The response has the following shape in event.detail:
+ * {
+ * containerSelector: "container-component_A",
+ * name: "component_A",
+ * tabSelector: "tab-component_A",
+ * topic: "openfin-DOM-event",
+ * type: "tab-dropped",
+ * uuid: "OpenFin POC",
+ * url: "http://openfin.co" // The url of the view linked to the dropped tab.
+ * }
+ * ```
+ */
+class Layout extends base_1$6.Base {
+ /**
+ * @internal
+ */
+ // eslint-disable-next-line no-shadow
+ constructor(identity, wire) {
+ super(wire);
+ /**
+ * @internal
+ * Lazily constructed {@link LayoutEntitiesClient} bound to this platform's client and identity
+ * The client is for {@link LayoutEntitiesController}
+ */
+ _Layout_layoutClient.set(this, new lazy_1.Lazy(async () => layout_entities_1.LayoutNode.newLayoutEntitiesClient(await this.platform.getClient(), layout_constants_1$1.LAYOUT_CONTROLLER_ID, this.identity)));
+ /**
+ * Replaces a Platform window's layout with a new layout.
+ *
+ * @remarks Any views that were in the old layout but not the new layout will be destroyed. Views will be assigned a randomly generated name to avoid collisions.
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const layout = fin.Platform.Layout.wrapSync(windowIdentity);
+ *
+ * const newLayout = {
+ * content: [
+ * {
+ * type: 'stack',
+ * content: [
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'new_component_A1',
+ * processAffinity: 'ps_1',
+ * url: 'https://www.example.com'
+ * }
+ * },
+ * {
+ * type: 'component',
+ * componentName: 'view',
+ * componentState: {
+ * name: 'new_component_A2',
+ * url: 'https://cdn.openfin.co/embed-web/chart.html'
+ * }
+ * }
+ * ]
+ * }
+ * ]
+ * };
+ *
+ * layout.replace(newLayout);
+ * ```
+ */
+ this.replace = async (layout) => {
+ this.wire.sendAction('layout-replace').catch((e) => {
+ // don't expose
+ });
+ const client = await this.platform.getClient();
+ await client.dispatch('replace-layout', {
+ target: this.identity,
+ opts: { layout }
+ });
+ };
+ /**
+ * Replaces the specified view with a view with the provided configuration.
+ *
+ * @remarks The old view is stripped of its listeners and either closed or attached to the provider window
+ * depending on `detachOnClose` view option.
+ *
+ * @param viewToReplace Identity of the view to be replaced
+ * @param newView Creation options of the new view.
+ *
+ * @example
+ * ```js
+ * let currentWindow;
+ * if (fin.me.isWindow) {
+ * currentWindow = fin.me;
+ * } else if (fin.me.isView) {
+ * currentWindow = await fin.me.getCurrentWindow();
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const layout = fin.Platform.Layout.wrapSync(currentWindow.identity);
+ * const viewToReplace = (await currentWindow.getCurrentViews())[0];
+ * const newViewConfig = {url: 'https://example.com'};
+ * await layout.replaceView(viewToReplace.identity, newViewConfig);
+ * ```
+ */
+ this.replaceView = async (viewToReplace, newView) => {
+ this.wire.sendAction('layout-replace-view').catch((e) => {
+ // don't expose
+ });
+ const client = await this.platform.getClient();
+ await client.dispatch('replace-view', {
+ target: this.identity,
+ opts: { viewToReplace, newView }
+ });
+ };
+ /**
+ * Replaces a Platform window's layout with a preset layout arrangement using the existing Views attached to the window.
+ * The preset options are `columns`, `grid`, `rows`, and `tabs`.
+ * @param options Mandatory object with `presetType` property that sets which preset layout arrangement to use.
+ * The preset options are `columns`, `grid`, `rows`, and `tabs`.
+ *
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const layout = fin.Platform.Layout.wrapSync(windowIdentity);
+ * await layout.applyPreset({ presetType: 'grid' });
+ *
+ * // wait 5 seconds until you change the layout from grid to tabs
+ * await new Promise (res => setTimeout(res, 5000));
+ * await layout.applyPreset({ presetType: 'tabs' });
+ * ```
+ */
+ this.applyPreset = async (options) => {
+ this.wire.sendAction('layout-apply-preset').catch((e) => {
+ // don't expose
+ });
+ const client = await this.platform.getClient();
+ const { presetType } = options;
+ if (!presetType || !(0, common_utils_1.isValidPresetType)(presetType)) {
+ throw new Error('Cannot apply preset layout, please include an applicable presetType property in the PresetLayoutOptions.');
+ }
+ await client.dispatch('apply-preset-layout', {
+ target: this.identity,
+ opts: { presetType }
+ });
+ };
+ const errorMsg = (0, validate_1.validateIdentity)(identity);
+ if (errorMsg) {
+ throw new Error(errorMsg);
+ }
+ this.identity = identity;
+ this.platform = this.fin.Platform.wrapSync({ uuid: identity.uuid });
+ if (identity.uuid === this.fin.me.uuid && identity.name === this.fin.me.name) {
+ this.init = this.fin.Platform.Layout.init;
+ }
+ }
+ /**
+ * Returns the configuration of the window's layout. Returns the same information that is returned for all windows in getSnapshot.
+ *
+ * @remarks Cannot be called from a View.
+ *
+ *
+ * @example
+ * ```js
+ * const layout = fin.Platform.Layout.getCurrentSync();
+ * // Use wrapped instance to get the layout configuration of the current window's Layout:
+ * const layoutConfig = await layout.getConfig();
+ * ```
+ */
+ async getConfig() {
+ this.wire.sendAction('layout-get-config').catch((e) => {
+ // don't expose
+ });
+ const client = await this.platform.getClient();
+ return client.dispatch('get-frame-snapshot', {
+ target: this.identity
+ });
+ }
+ /**
+ * Retrieves the attached views in current window layout.
+ *
+ * @example
+ * ```js
+ * const layout = fin.Platform.Layout.getCurrentSync();
+ * const views = await layout.getCurrentViews();
+ * ```
+ */
+ async getCurrentViews() {
+ this.wire.sendAction('layout-get-views').catch((e) => {
+ // don't expose
+ });
+ const client = await this.platform.getClient();
+ const viewIdentities = await client.dispatch('get-layout-views', {
+ target: this.identity
+ });
+ return viewIdentities.map((identity) => this.fin.View.wrapSync(identity));
+ }
+ /**
+ * Retrieves the top level content item of the layout.
+ *
+ * @remarks Cannot be called from a view.
+ *
+ *
+ *
+ * @example
+ * ```js
+ * if (!fin.me.isWindow) {
+ * throw new Error('Not running in a platform View.');
+ * }
+ *
+ * // From the layout window
+ * const layout = fin.Platform.Layout.getCurrentSync();
+ * // Retrieves the ColumnOrRow instance
+ * const rootItem = await layout.getRootItem();
+ * const content = await rootItem.getContent();
+ * console.log(`The root ColumnOrRow instance has ${content.length} item(s)`);
+ * ```
+ */
+ async getRootItem() {
+ this.wire.sendAction('layout-get-root-item').catch(() => {
+ // don't expose
+ });
+ const client = await __classPrivateFieldGet$5(this, _Layout_layoutClient, "f").getValue();
+ const root = await client.getRoot('layoutName' in this.identity ? this.identity : undefined);
+ return layout_entities_1.LayoutNode.getEntity(root, client);
+ }
+}
+Instance$1.Layout = Layout;
+_Layout_layoutClient = new WeakMap();
+
+var __classPrivateFieldGet$4 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __classPrivateFieldSet$4 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var _LayoutModule_instances, _LayoutModule_layoutInitializationAttempted, _LayoutModule_layoutManager, _LayoutModule_throwIfLayoutManagerNotInitialized;
+Object.defineProperty(Factory$2, "__esModule", { value: true });
+Factory$2.LayoutModule = void 0;
+const base_1$5 = base;
+const Instance_1$2 = Instance$1;
+const layout_constants_1 = layout_constants;
+/**
+ * Static namespace for OpenFin API methods that interact with the {@link Layout} class, available under `fin.Platform.Layout`.
+ */
+class LayoutModule extends base_1$5.Base {
+ constructor() {
+ super(...arguments);
+ _LayoutModule_instances.add(this);
+ _LayoutModule_layoutInitializationAttempted.set(this, false);
+ _LayoutModule_layoutManager.set(this, null);
+ /**
+ * Initialize the window's Layout.
+ *
+ * @remarks Must be called from a custom window that has a 'layout' option set upon creation of that window.
+ * If a containerId is not provided, this method attempts to find an element with the id `layout-container`.
+ * A Layout will emit events locally on the DOM element representing the layout-container.
+ * In order to capture the relevant events during Layout initiation, set up the listeners on the DOM element prior to calling `init`.
+ * @param options - Layout init options.
+ *
+ * @experimental
+ *
+ * @example
+ * ```js
+ * // If no options are included, the layout in the window options is initialized in an element with the id `layout-container`
+ * const layout = await fin.Platform.Layout.init();
+ * ```
+ *
+ *
+ * ```js
+ * const containerId = 'my-custom-container-id';
+ *
+ * const myLayoutContainer = document.getElementById(containerId);
+ *
+ * myLayoutContainer.addEventListener('tab-created', function(event) {
+ * const { tabSelector } = event.detail;
+ * const tabElement = document.getElementById(tabSelector);
+ * const existingColor = tabElement.style.backgroundColor;
+ * tabElement.style.backgroundColor = "red";
+ * setTimeout(() => {
+ * tabElement.style.backgroundColor = existingColor;
+ * }, 2000);
+ * });
+ *
+ * // initialize the layout into an existing HTML element with the div `my-custom-container-id`
+ * // the window must have been created with a layout in its window options
+ * const layout = await fin.Platform.Layout.init({ containerId });
+ * ```
+ */
+ this.init = async (options = {}) => {
+ this.wire.sendAction('layout-init').catch((e) => {
+ // don't expose
+ });
+ if (!this.fin.me.isWindow) {
+ throw new Error('Layout.init can only be called from a Window context.');
+ }
+ else if (__classPrivateFieldGet$4(this, _LayoutModule_layoutInitializationAttempted, "f")) {
+ throw new Error('Layout.init was already called, please use Layout.create to add additional layouts.');
+ }
+ __classPrivateFieldSet$4(this, _LayoutModule_layoutInitializationAttempted, true, "f");
+ // preload the client
+ await this.fin.Platform.getCurrentSync().getClient();
+ __classPrivateFieldSet$4(this, _LayoutModule_layoutManager, await this.wire.environment.initLayoutManager(this.fin, this.wire, options), "f");
+ await this.wire.environment.applyLayoutSnapshot(this.fin, __classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f"), options);
+ if (!options.layoutManagerOverride) {
+ // in single-layout case, we return the undocumented layoutManager type (deprecate with CORE-1081)
+ const layoutIdentity = { layoutName: layout_constants_1.DEFAULT_LAYOUT_KEY, ...this.fin.me.identity };
+ const layoutManager = await this.wire.environment.resolveLayout(__classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f"), layoutIdentity);
+ return Object.assign(this.wrapSync(layoutIdentity), { layoutManager });
+ }
+ return this.wrapSync(this.fin.me.identity);
+ };
+ /**
+ * Returns the layout manager for the current window
+ * @returns
+ */
+ this.getCurrentLayoutManagerSync = () => {
+ __classPrivateFieldGet$4(this, _LayoutModule_instances, "m", _LayoutModule_throwIfLayoutManagerNotInitialized).call(this, `fin.Platform.Layout.getCurrentLayoutManagerSync()`);
+ // @ts-expect-error User may have implemented their own snapshot type when overriding LayoutManager
+ return __classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f");
+ };
+ this.create = async (options) => {
+ __classPrivateFieldGet$4(this, _LayoutModule_instances, "m", _LayoutModule_throwIfLayoutManagerNotInitialized).call(this, `fin.Platform.Layout.create()`);
+ return this.wire.environment.createLayout(__classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f"), options);
+ };
+ this.destroy = async (layoutIdentity) => {
+ __classPrivateFieldGet$4(this, _LayoutModule_instances, "m", _LayoutModule_throwIfLayoutManagerNotInitialized).call(this, `fin.Platform.Layout.destroy()`);
+ return this.wire.environment.destroyLayout(__classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f"), layoutIdentity);
+ };
+ }
+ /**
+ * Asynchronously returns a Layout object that represents a Window's layout.
+ *
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (!fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const layout = await fin.Platform.Layout.wrap(windowIdentity);
+ * // Use wrapped instance to control layout, e.g.:
+ * const layoutConfig = await layout.getConfig();
+ * ```
+ */
+ async wrap(identity) {
+ this.wire.sendAction('layout-wrap').catch((e) => {
+ // don't expose
+ });
+ return new Instance_1$2.Layout(identity, this.wire);
+ }
+ /**
+ * Synchronously returns a Layout object that represents a Window's layout.
+ *
+ * @example
+ * ```js
+ * let windowIdentity;
+ * if (!fin.me.isWindow) {
+ * windowIdentity = fin.me.identity;
+ * } else if (fin.me.isView) {
+ * windowIdentity = (await fin.me.getCurrentWindow()).identity;
+ * } else {
+ * throw new Error('Not running in a platform View or Window');
+ * }
+ *
+ * const layout = fin.Platform.Layout.wrapSync(windowIdentity);
+ * // Use wrapped instance to control layout, e.g.:
+ * const layoutConfig = await layout.getConfig();
+ * ```
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('layout-wrap-sync').catch((e) => {
+ // don't expose
+ });
+ return new Instance_1$2.Layout(identity, this.wire);
+ }
+ /**
+ * Asynchronously returns a Layout object that represents a Window's layout.
+ *
+ * @example
+ * ```js
+ * const layout = await fin.Platform.Layout.getCurrent();
+ * // Use wrapped instance to control layout, e.g.:
+ * const layoutConfig = await layout.getConfig();
+ * ```
+ */
+ async getCurrent() {
+ this.wire.sendAction('layout-get-current').catch((e) => {
+ // don't expose
+ });
+ if (!this.fin.me.isWindow) {
+ throw new Error('You are not in a Window context. Only Windows can have a Layout.');
+ }
+ const { uuid, name } = this.fin.me;
+ return this.wrap({ uuid, name });
+ }
+ /**
+ * Synchronously returns a Layout object that represents a Window's layout.
+ *
+ * @remarks Cannot be called from a view.
+ *
+ *
+ * @example
+ * ```js
+ * const layout = fin.Platform.Layout.getCurrentSync();
+ * // Use wrapped instance to control layout, e.g.:
+ * const layoutConfig = await layout.getConfig();
+ * ```
+ */
+ getCurrentSync() {
+ this.wire.sendAction('layout-get-current-sync').catch((e) => {
+ // don't expose
+ });
+ if (!this.fin.me.isWindow) {
+ throw new Error('You are not in a Window context. Only Windows can have a Layout.');
+ }
+ const { uuid, name } = this.fin.me;
+ return this.wrapSync({ uuid, name });
+ }
+}
+Factory$2.LayoutModule = LayoutModule;
+_LayoutModule_layoutInitializationAttempted = new WeakMap(), _LayoutModule_layoutManager = new WeakMap(), _LayoutModule_instances = new WeakSet(), _LayoutModule_throwIfLayoutManagerNotInitialized = function _LayoutModule_throwIfLayoutManagerNotInitialized(method) {
+ if (!__classPrivateFieldGet$4(this, _LayoutModule_layoutManager, "f")) {
+ throw new Error(`You must call init before using the API ${method}`);
+ }
+};
+
+(function (exports) {
+ /**
+ * Entry point for the OpenFin `Layout` subset of the `Platform` API (`fin.Platform.Layout`).
+ *
+ * * {@link LayoutModule} contains static members of the `Layout` API, accessible through `fin.Platform.Layout`.
+ * * {@link Layout} describes an instance of an OpenFin Layout, e.g. as returned by `fin.Platform.Layout.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ *
+ */
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(Factory$2, exports);
+ __exportStar(Instance$1, exports);
+} (layout));
+
+Object.defineProperty(Factory$3, "__esModule", { value: true });
+Factory$3.PlatformModule = void 0;
+const base_1$4 = base;
+const Instance_1$1 = Instance$2;
+const index_1$1 = layout;
+/**
+ * Static namespace for OpenFin API methods that interact with the {@link Platform} class, available under `fin.Platform`.
+ */
+class PlatformModule extends base_1$4.Base {
+ /**
+ * @internal
+ */
+ constructor(wire, channel) {
+ super(wire);
+ this._channel = channel;
+ /**
+ *
+ * @desc Layouts give app providers the ability to embed multiple views in a single window. The Layout namespace
+ * enables the initialization and manipulation of a window's Layout. A Layout will
+ * emit events locally on the DOM element representing the layout-container.
+ */
+ this.Layout = new index_1$1.LayoutModule(this.wire);
+ }
+ /**
+ * Initializes a Platform. Must be called from the Provider when using a custom provider.
+ * @param options - platform options including a callback function that can be used to extend or replace
+ * default Provider behavior.
+ *
+ * @remarks Must be called from the Provider when using a custom provider.
+ *
+ * @example
+ *
+ * ```js
+ * // From Provider context
+ * await fin.Platform.init();
+ * // Platform API is now hooked up and windows contained in the manifest snapshot are open.
+ * ```
+ *
+ * `Platform.init` accepts an options object that can contain a callback function which can be used to extend or
+ * replace default Provider behavior. As an argument, this function will receive the `Provider` class, which is
+ * used to handle Platform actions. The function must return an object with methods to handle Platform API actions.
+ * The recommended approach is to extend the `Provider` class, overriding the methods you wish to alter, and return an
+ * instance of your subclass:
+ *
+ * ```js
+ * const overrideCallback = async (PlatformProvider) => {
+ * // Actions can be performed before initialization.
+ * // e.g. we might authenticate a user, set up a Channel, etc before initializing the Platform.
+ * const { manifestUrl } = await fin.Application.getCurrentSync().getInfo();
+ *
+ * // Extend or replace default PlatformProvider behavior by extending the PlatformProvider class.
+ * class MyOverride extends PlatformProvider {
+ * // Default behavior can be changed by implementing methods with the same names as those used by the default PlatformProvider.
+ * async getSnapshot() {
+ * // Since we are extending the class, we can call `super` methods to access default behavior.
+ * const snapshot = await super.getSnapshot();
+ * // But we can modify return values.
+ * return { ...snapshot, answer: 42, manifestUrl };
+ * }
+ * async replaceLayout({ opts, target }) {
+ * // To disable an API method, overwrite with a noop function.
+ * return;
+ * }
+ * }
+ * // Return instance with methods to be consumed by Platform.
+ * // The returned object must implement all methods of the PlatformProvider class.
+ * // By extending the class, we can simply inherit methods we do not wish to alter.
+ * return new MyOverride();
+ * };
+ *
+ * fin.Platform.init({overrideCallback});
+ * ```
+ * @experimental
+ */
+ async init(options) {
+ if (!fin.__internal_.isPlatform || fin.me.name !== fin.me.uuid) {
+ throw new Error('fin.Platform.init should only be called from a custom platform provider running in the main window of the application.');
+ }
+ return this.wire.environment.initPlatform(this.fin, options);
+ }
+ /**
+ * Asynchronously returns a Platform object that represents an existing platform.
+ *
+ * @example
+ * ```js
+ * const { identity } = fin.me;
+ * const platform = await fin.Platform.wrap(identity);
+ * // Use wrapped instance to control layout, e.g.:
+ * const snapshot = await platform.getSnapshot();
+ * ```
+ */
+ async wrap(identity) {
+ this.wire.sendAction('platform-wrap').catch((e) => {
+ // don't expose
+ });
+ return new Instance_1$1.Platform({ uuid: identity.uuid }, this._channel);
+ }
+ /**
+ * Synchronously returns a Platform object that represents an existing platform.
+ *
+ * @example
+ * ```js
+ * const { identity } = fin.me;
+ * const platform = fin.Platform.wrapSync(identity);
+ * // Use wrapped instance to control layout, e.g.:
+ * const snapshot = await platform.getSnapshot();
+ * ```
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('platform-wrap-sync').catch((e) => {
+ // don't expose
+ });
+ return new Instance_1$1.Platform({ uuid: identity.uuid }, this._channel);
+ }
+ /**
+ * Asynchronously returns a Platform object that represents the current platform.
+ *
+ * @example
+ * ```js
+ * const platform = await fin.Platform.getCurrent();
+ * // Use wrapped instance to control layout, e.g.:
+ * const snapshot = await platform.getSnapshot();
+ * ```
+ */
+ async getCurrent() {
+ this.wire.sendAction('platform-get-current').catch((e) => {
+ // don't expose
+ });
+ return this.wrap({ uuid: this.wire.me.uuid });
+ }
+ /**
+ * Synchronously returns a Platform object that represents the current platform.
+ *
+ * @example
+ * ```js
+ * const platform = fin.Platform.getCurrentSync();
+ * // Use wrapped instance to control layout, e.g.:
+ * const snapshot = await platform.getSnapshot();
+ * ```
+ */
+ getCurrentSync() {
+ this.wire.sendAction('platform-get-current-sync').catch((e) => {
+ // don't expose
+ });
+ return this.wrapSync({ uuid: this.wire.me.uuid });
+ }
+ /**
+ * Creates and starts a Platform and returns a wrapped and running Platform instance. The wrapped Platform methods can
+ * be used to launch content into the platform. Promise will reject if the platform is already running.
+ *
+ * @example
+ * ```js
+ * try {
+ * const platform = await fin.Platform.start({
+ * uuid: 'platform-1',
+ * autoShow: false,
+ * defaultWindowOptions: {
+ * stylesheetUrl: 'css-sheet-url',
+ * cornerRounding: {
+ * height: 10,
+ * width: 10
+ * }
+ * }
+ * });
+ * console.log('Platform is running', platform);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * ```
+ */
+ start(platformOptions) {
+ this.wire.sendAction('platform-start').catch((e) => {
+ // don't expose
+ });
+ // eslint-disable-next-line no-async-promise-executor
+ return new Promise(async (resolve, reject) => {
+ try {
+ const { uuid } = platformOptions;
+ // @ts-expect-error using private variable.
+ const app = await this.fin.Application._create({ ...platformOptions, isPlatformController: true });
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ app.once('platform-api-ready', () => resolve(this.wrapSync({ uuid })));
+ // @ts-expect-error using private variable.
+ app._run({ uuid });
+ }
+ catch (e) {
+ reject(e);
+ }
+ });
+ }
+ /**
+ * Retrieves platforms's manifest and returns a wrapped and running Platform. If there is a snapshot in the manifest,
+ * it will be launched into the platform.
+ * @param manifestUrl - The URL of platform's manifest.
+ * @param opts - Parameters that the RVM will use.
+ *
+ * @example
+ * ```js
+ * try {
+ * const platform = await fin.Platform.startFromManifest('https://openfin.github.io/golden-prototype/public.json');
+ * console.log('Platform is running, wrapped platform: ', platform);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * // For a local manifest file:
+ * try {
+ * const platform = await fin.Platform.startFromManifest('file:///C:/somefolder/app.json');
+ * console.log('Platform is running, wrapped platform: ', platform);
+ * } catch(e) {
+ * console.error(e);
+ * }
+ * ```
+ */
+ startFromManifest(manifestUrl, opts) {
+ this.wire.sendAction('platform-start-from-manifest').catch((e) => {
+ // don't expose
+ });
+ // eslint-disable-next-line no-async-promise-executor
+ return new Promise(async (resolve, reject) => {
+ try {
+ // @ts-expect-error using private variable.
+ const app = await this.fin.Application._createFromManifest(manifestUrl);
+ // TODO: fix typing (internal)
+ // @ts-expect-error
+ app.once('platform-api-ready', () => resolve(this.wrapSync({ uuid: app.identity.uuid })));
+ // @ts-expect-error using private method without warning.
+ app._run(opts);
+ }
+ catch (e) {
+ reject(e);
+ }
+ });
+ }
+}
+Factory$3.PlatformModule = PlatformModule;
+
+(function (exports) {
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ /**
+ * Entry points for the OpenFin `Platform` API (`fin.Platform`)
+ *
+ * * {@link PlatformModule} contains static members of the `Platform` API, accessible through `fin.Platform`.
+ * * {@link Platform} describes an instance of an OpenFin Platform, e.g. as returned by `fin.Platform.getCurrent`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ */
+ __exportStar(Factory$3, exports);
+ __exportStar(Instance$2, exports);
+} (platform));
+
+var me = {};
+
+(function (exports) {
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.getMe = exports.getBaseMe = exports.environmentUnsupportedMessage = void 0;
+ const view_1 = requireView();
+ const frame_1 = frame;
+ const window_1 = requireWindow();
+ const external_application_1 = externalApplication;
+ exports.environmentUnsupportedMessage = 'You are not running in OpenFin.';
+ function getBaseMe(entityType, uuid, name) {
+ const entityTypeHelpers = {
+ isView: entityType === 'view',
+ isWindow: entityType === 'window',
+ isFrame: entityType === 'iframe',
+ isExternal: entityType === 'external connection'
+ };
+ return { ...entityTypeHelpers, uuid, name, entityType };
+ }
+ exports.getBaseMe = getBaseMe;
+ // We need to do a lot of casting as unknown here because the compiler get's confused about matching types. What matters is that it works on the outside
+ function getMe(wire) {
+ const { uuid, name, entityType } = wire.me;
+ const unsupportedInterop = {
+ setContext() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ addContextHandler() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ getContextGroups() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ joinContextGroup() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ removeFromContextGroup() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ getAllClientsInContextGroup() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ getInfoForContextGroup() {
+ throw new Error(exports.environmentUnsupportedMessage);
+ }
+ };
+ const fallbackErrorMessage = 'Interop API has not been instantiated. Either connection has failed or you have not declared interop in your config.';
+ const fallbackInterop = {
+ setContext() {
+ throw new Error(fallbackErrorMessage);
+ },
+ addContextHandler() {
+ throw new Error(fallbackErrorMessage);
+ },
+ getContextGroups() {
+ throw new Error(fallbackErrorMessage);
+ },
+ joinContextGroup() {
+ throw new Error(fallbackErrorMessage);
+ },
+ removeFromContextGroup() {
+ throw new Error(fallbackErrorMessage);
+ },
+ getAllClientsInContextGroup() {
+ throw new Error(fallbackErrorMessage);
+ },
+ getInfoForContextGroup() {
+ throw new Error(fallbackErrorMessage);
+ }
+ };
+ const unsupportedEventBase = {
+ eventNames: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ emit: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ listeners: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ listenerCount: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ on: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ addListener: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ once: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ prependListener: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ prependOnceListener: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ removeListener: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ },
+ removeAllListeners: () => {
+ throw new Error(exports.environmentUnsupportedMessage);
+ }
+ };
+ switch (entityType) {
+ case 'view':
+ return Object.assign(new view_1.View(wire, { uuid, name }), getBaseMe(entityType, uuid, name), {
+ interop: fallbackInterop,
+ isOpenFin: true
+ });
+ case 'window':
+ return Object.assign(new window_1._Window(wire, { uuid, name }), getBaseMe(entityType, uuid, name), {
+ interop: fallbackInterop,
+ isOpenFin: true
+ });
+ case 'iframe':
+ return Object.assign(new frame_1._Frame(wire, { uuid, name }), getBaseMe(entityType, uuid, name), {
+ interop: fallbackInterop,
+ isOpenFin: true
+ });
+ case 'external connection':
+ return Object.assign(new external_application_1.ExternalApplication(wire, { uuid }), getBaseMe(entityType, uuid, name), {
+ interop: fallbackInterop,
+ isOpenFin: false
+ });
+ default:
+ return {
+ ...getBaseMe(entityType, uuid, name),
+ ...unsupportedEventBase,
+ interop: unsupportedInterop,
+ isOpenFin: false
+ };
+ }
+ }
+ exports.getMe = getMe;
+} (me));
+
+var interop = {};
+
+var Factory$1 = {};
+
+var inaccessibleObject = {};
+
+Object.defineProperty(inaccessibleObject, "__esModule", { value: true });
+inaccessibleObject.createWarningObject = inaccessibleObject.createUnusableObject = void 0;
+function createUnusableObject(message) {
+ const handle = () => {
+ throw new Error(message);
+ };
+ return new Proxy({}, {
+ apply: handle,
+ construct: handle,
+ defineProperty: handle,
+ deleteProperty: handle,
+ get: handle,
+ getOwnPropertyDescriptor: handle,
+ getPrototypeOf: handle,
+ has: handle,
+ isExtensible: handle,
+ ownKeys: handle,
+ preventExtensions: handle,
+ set: handle,
+ setPrototypeOf: handle
+ });
+}
+inaccessibleObject.createUnusableObject = createUnusableObject;
+function createWarningObject(message, obj) {
+ return new Proxy(obj, {
+ get: (...args) => {
+ // eslint-disable-next-line no-console
+ console.warn(message);
+ return Reflect.get(...args);
+ },
+ set: (...args) => {
+ // eslint-disable-next-line no-console
+ console.warn(message);
+ return Reflect.set(...args);
+ },
+ getOwnPropertyDescriptor: (...args) => {
+ // eslint-disable-next-line no-console
+ console.warn(message);
+ return Reflect.getOwnPropertyDescriptor(...args);
+ },
+ ownKeys: (...args) => {
+ // eslint-disable-next-line no-console
+ console.warn(message);
+ return Reflect.ownKeys(...args);
+ }
+ });
+}
+inaccessibleObject.createWarningObject = createWarningObject;
+
+var InteropBroker = {};
+
+var SessionContextGroupBroker = {};
+
+var hasRequiredSessionContextGroupBroker;
+
+function requireSessionContextGroupBroker () {
+ if (hasRequiredSessionContextGroupBroker) return SessionContextGroupBroker;
+ hasRequiredSessionContextGroupBroker = 1;
+ Object.defineProperty(SessionContextGroupBroker, "__esModule", { value: true });
+ const _1 = requireInterop();
+ let SessionContextGroupBroker$1 = class SessionContextGroupBroker {
+ constructor(provider, id) {
+ this.provider = provider;
+ this.id = id;
+ this.lastContext = undefined;
+ this.contextGroupMap = new Map();
+ this.clients = new Map();
+ this.registerListeners();
+ }
+ registerListeners() {
+ this.provider.register(`sessionContextGroup:getContext-${this.id}`, this.getCurrentContext.bind(this));
+ this.provider.register(`sessionContextGroup:setContext-${this.id}`, this.setContext.bind(this));
+ this.provider.register(`sessionContextGroup:handlerAdded-${this.id}`, this.handlerAdded.bind(this));
+ this.provider.register(`sessionContextGroup:handlerRemoved-${this.id}`, this.handlerRemoved.bind(this));
+ }
+ getCurrentContext(payload) {
+ return payload.type ? this.contextGroupMap.get(payload.type) : this.lastContext;
+ }
+ setContext(payload, clientIdentity) {
+ const { context } = payload;
+ const contextIntegrityCheckResult = _1.InteropBroker.checkContextIntegrity(context);
+ if (contextIntegrityCheckResult.isValid === false) {
+ throw new Error(`Failed to set Context - bad Context. Reason: ${contextIntegrityCheckResult.reason}. Context: ${JSON.stringify(context)}`);
+ }
+ const clientState = this.getClientState(clientIdentity);
+ if (!clientState) {
+ // This shouldn't get hit.
+ throw new Error(`Client with Identity: ${clientIdentity.uuid} ${clientIdentity.name} not in Session Client State Map`);
+ }
+ // set the context
+ this.contextGroupMap.set(context.type, context);
+ this.lastContext = context;
+ const clientSubscriptionStates = Array.from(this.clients.values());
+ clientSubscriptionStates.forEach((client) => {
+ // eslint-disable-next-line no-unused-expressions
+ client.contextHandlers.get(context.type)?.forEach((handlerId) => {
+ this.provider.dispatch(client.clientIdentity, handlerId, context);
+ });
+ if (client.globalHandler) {
+ this.provider.dispatch(client.clientIdentity, client.globalHandler, context);
+ }
+ });
+ }
+ getClientState(id) {
+ return this.clients.get(id.endpointId);
+ }
+ async handlerAdded(payload, clientIdentity) {
+ const { handlerId, contextType } = payload;
+ const clientSubscriptionState = this.getClientState(clientIdentity);
+ if (!clientSubscriptionState) {
+ throw new Error(`Client with Identity: ${clientIdentity.uuid} ${clientIdentity.name} not in Client State Map`);
+ }
+ if (contextType) {
+ const currentHandlerList = clientSubscriptionState.contextHandlers.get(contextType) || [];
+ clientSubscriptionState.contextHandlers.set(contextType, [...currentHandlerList, handlerId]);
+ const currentContext = this.contextGroupMap.get(contextType);
+ if (currentContext) {
+ await this.provider.dispatch(clientIdentity, handlerId, currentContext);
+ }
+ }
+ else {
+ clientSubscriptionState.globalHandler = handlerId;
+ const globalDispatchPromises = [...this.contextGroupMap.keys()].map(async (currentContextType) => {
+ const currentContext = this.contextGroupMap.get(currentContextType);
+ if (currentContext) {
+ await this.provider.dispatch(clientIdentity, handlerId, currentContext);
+ }
+ });
+ await Promise.all(globalDispatchPromises);
+ }
+ }
+ handlerRemoved(payload, clientIdentity) {
+ const { handlerId } = payload;
+ const client = this.clients.get(clientIdentity.endpointId);
+ if (client) {
+ Array.from(client.contextHandlers).forEach(([, handlers]) => {
+ const index = handlers.indexOf(handlerId);
+ if (index > -1) {
+ handlers.splice(index, 1);
+ }
+ });
+ if (client.globalHandler === handlerId) {
+ client.globalHandler = undefined;
+ }
+ }
+ else {
+ console.warn(`Trying to remove a handler from a client that isn't mapped. handlerId: ${handlerId}. clientIdentity: ${clientIdentity}`);
+ }
+ }
+ registerNewClient(clientIdentity) {
+ if (!this.clients.has(clientIdentity.endpointId)) {
+ const clientSubscriptionState = {
+ contextHandlers: new Map(),
+ clientIdentity,
+ globalHandler: undefined
+ };
+ this.clients.set(clientIdentity.endpointId, clientSubscriptionState);
+ }
+ }
+ onDisconnection(clientIdentity) {
+ this.clients.delete(clientIdentity.endpointId);
+ }
+ };
+ SessionContextGroupBroker.default = SessionContextGroupBroker$1;
+ return SessionContextGroupBroker;
+}
+
+var utils$1 = {};
+
+(function (exports) {
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.wrapIntentHandler = exports.BROKER_ERRORS = exports.generateOverrideWarning = exports.generateOverrideError = exports.wrapContextHandler = exports.wrapInTryCatch = exports.generateId = void 0;
+ const generateId = () => `${Math.random()}${Date.now()}`;
+ exports.generateId = generateId;
+ const wrapInTryCatch = (f, prefix) => (...args) => {
+ try {
+ return f(...args);
+ }
+ catch (e) {
+ throw new Error((prefix || '') + e);
+ }
+ };
+ exports.wrapInTryCatch = wrapInTryCatch;
+ const wrapContextHandler = (handler, handlerId) => {
+ return async (context) => {
+ try {
+ await handler(context);
+ }
+ catch (error) {
+ console.error(`Error thrown by handler ${handlerId} for context type ${context.type}: ${error}`);
+ throw error;
+ }
+ };
+ };
+ exports.wrapContextHandler = wrapContextHandler;
+ const generateOverrideError = (clientApi, brokerApi) => {
+ return `You have tried to to use ${clientApi} but ${brokerApi} has not been overridden in the Interop Broker. Please override this function. Refer to our documentation for more info.`;
+ };
+ exports.generateOverrideError = generateOverrideError;
+ const generateOverrideWarning = (fdc3ClientApi, brokerApi, identity, interopClientApi) => {
+ const { uuid, name } = identity;
+ const message = interopClientApi
+ ? `Entity with identity: ${uuid}/${name} has called ${interopClientApi} or ${fdc3ClientApi} but ${brokerApi} has not been overridden.`
+ : `Entity with identity: ${uuid}/${name} has called ${fdc3ClientApi} but ${brokerApi} has not been overridden.`;
+ return message;
+ };
+ exports.generateOverrideWarning = generateOverrideWarning;
+ exports.BROKER_ERRORS = {
+ fireIntent: (0, exports.generateOverrideError)('fireIntent', 'handleFiredIntent'),
+ fireIntentForContext: (0, exports.generateOverrideError)('fireIntentForContext', 'handleFiredIntentForContext'),
+ getInfoForIntent: (0, exports.generateOverrideError)('getInfoForIntent', 'handleInfoForIntent'),
+ getInfoForIntentsByContext: (0, exports.generateOverrideError)('getInfoForIntentsByContext', 'handleInfoForIntentsByContext'),
+ joinSessionContextGroupWithJoinContextGroup: 'The Context Group you have tried to join is a Session Context Group. Custom Context Groups can only be defined by the Interop Broker through code or manifest configuration. Please use joinSessionContextGroup.',
+ fdc3Open: (0, exports.generateOverrideError)('fdc3.open', 'fdc3HandleOpen'),
+ fdc3FindInstances: (0, exports.generateOverrideError)('fdc3.findInstances', 'fdc3HandleFindInstances'),
+ fdc3GetAppMetadata: (0, exports.generateOverrideError)('fdc3.getAppMetadata', 'fdc3HandleGetAppMetadata'),
+ fdc3GetInfo: (0, exports.generateOverrideError)('fdc3.getInfo', 'fdc3HandleGetInfo')
+ };
+ const wrapIntentHandler = (handler, handlerId) => {
+ return async (intent) => {
+ try {
+ return handler(intent);
+ }
+ catch (error) {
+ console.error(`Error thrown by handler ${handlerId}: ${error}`);
+ throw error;
+ }
+ };
+ };
+ exports.wrapIntentHandler = wrapIntentHandler;
+} (utils$1));
+
+var PrivateChannelProvider = {};
+
+var hasRequiredPrivateChannelProvider;
+
+function requirePrivateChannelProvider () {
+ if (hasRequiredPrivateChannelProvider) return PrivateChannelProvider;
+ hasRequiredPrivateChannelProvider = 1;
+ Object.defineProperty(PrivateChannelProvider, "__esModule", { value: true });
+ PrivateChannelProvider.PrivateChannelProvider = void 0;
+ const InteropBroker_1 = requireInteropBroker();
+ let PrivateChannelProvider$1 = class PrivateChannelProvider {
+ constructor(provider, id) {
+ this.provider = provider;
+ this.id = id;
+ this.clients = new Map();
+ this.registerListeners();
+ this.contextByContextType = new Map();
+ this.lastContext = undefined;
+ this.provider.onConnection((clientIdentity) => this.registerNewClient(clientIdentity));
+ this.provider.onDisconnection(async (clientIdentity) => {
+ const { endpointId } = clientIdentity;
+ if (this.clients.has(endpointId)) {
+ await this.handleClientDisconnecting(clientIdentity);
+ }
+ if ((await this.provider.getAllClientInfo()).length === 0) {
+ this.provider.destroy();
+ }
+ });
+ }
+ getClientState(id) {
+ return this.clients.get(id.endpointId);
+ }
+ registerListeners() {
+ this.provider.register('broadcast', this.broadcast.bind(this));
+ this.provider.register('getCurrentContext', this.getCurrentContext.bind(this));
+ this.provider.register('contextHandlerAdded', this.contextHandlerAdded.bind(this));
+ this.provider.register('contextHandlerRemoved', this.contextHandlerRemoved.bind(this));
+ this.provider.register('nonStandardHandlerRemoved', this.nonStandardHandlerRemoved.bind(this));
+ this.provider.register('onAddContextHandlerAdded', this.onAddContextHandlerAdded.bind(this));
+ this.provider.register('onDisconnectHandlerAdded', this.onDisconnectHandlerAdded.bind(this));
+ this.provider.register('onUnsubscribeHandlerAdded', this.onUnsubscribeHandlerAdded.bind(this));
+ this.provider.register('clientDisconnecting', (payload, clientIdentity) => {
+ this.handleClientDisconnecting(clientIdentity);
+ });
+ }
+ broadcast(payload, broadcasterClientIdentity) {
+ const { context } = payload;
+ const broadcasterClientState = this.getClientState(broadcasterClientIdentity);
+ if (!broadcasterClientState) {
+ throw new Error(`Client with Identity: ${broadcasterClientIdentity.uuid} ${broadcasterClientIdentity.name}, tried to call broadcast, is not connected to this Private Channel`);
+ }
+ const contextIntegrityCheckResult = InteropBroker_1.InteropBroker.checkContextIntegrity(context);
+ if (contextIntegrityCheckResult.isValid === false) {
+ throw new Error(`Failed to broadcast - bad Context. Reason: ${contextIntegrityCheckResult.reason}. Context: ${JSON.stringify(context)}`);
+ }
+ this.contextByContextType.set(context.type, context);
+ this.lastContext = context;
+ Array.from(this.clients.values()).forEach((currClientState) => {
+ const handlerIdsForContextType = currClientState.handlerIdsByContextTypes.get(context.type);
+ if (handlerIdsForContextType) {
+ handlerIdsForContextType.forEach((handlerId) => {
+ this.provider.dispatch(currClientState.clientIdentity, handlerId, context);
+ });
+ }
+ if (currClientState.globalHandler) {
+ this.provider.dispatch(currClientState.clientIdentity, currClientState.globalHandler, context);
+ }
+ });
+ }
+ getCurrentContext(payload, senderClientIdentity) {
+ const { contextType } = payload;
+ const clientState = this.getClientState(senderClientIdentity);
+ if (!clientState) {
+ throw new Error(`Client with Identity: ${senderClientIdentity.uuid} ${senderClientIdentity.name}, tried to call getCurrentContext, is not connected to this Private Channel`);
+ }
+ if (contextType !== undefined) {
+ const currentContext = this.contextByContextType.get(contextType);
+ if (currentContext)
+ return currentContext;
+ return null;
+ }
+ return this.lastContext ? this.lastContext : null;
+ }
+ contextHandlerAdded(payload, senderClientIdentity) {
+ const { handlerId, contextType } = payload;
+ const senderClientState = this.getClientState(senderClientIdentity);
+ if (!senderClientState) {
+ throw new Error(`Client with Identity: ${senderClientIdentity.uuid} ${senderClientIdentity.name}, tried to call addContextListener, is not connected to this Private Channel`);
+ }
+ if (contextType) {
+ const currentHandlersList = senderClientState.handlerIdsByContextTypes.get(contextType) || [];
+ senderClientState.handlerIdsByContextTypes.set(contextType, [...currentHandlersList, handlerId]);
+ }
+ else {
+ senderClientState.globalHandler = handlerId;
+ }
+ Array.from(this.clients.values()).forEach((currClientState) => {
+ if (currClientState.clientIdentity.endpointId !== senderClientIdentity.endpointId &&
+ currClientState.onAddContextListenerHandlerId) {
+ this.provider.dispatch(currClientState.clientIdentity, currClientState.onAddContextListenerHandlerId, contextType);
+ }
+ });
+ }
+ async contextHandlerRemoved(payload, removingClientIdentity) {
+ // MC: Made this removal async to ensure that onUnsubscribe handlers are hit before anything else happens.
+ const { handlerId } = payload;
+ const removingClientState = this.getClientState(removingClientIdentity);
+ if (removingClientState) {
+ let contextType;
+ if (removingClientState.globalHandler === handlerId) {
+ removingClientState.globalHandler = undefined;
+ }
+ else {
+ for (const [currContextType, handlersIds] of removingClientState.handlerIdsByContextTypes) {
+ const index = handlersIds.indexOf(handlerId);
+ if (index > -1) {
+ handlersIds.splice(index, 1);
+ contextType = currContextType;
+ }
+ }
+ }
+ // getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
+ // so we need to ensure we don't dispatch to any disconnected client
+ // TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
+ const clientsToDispatchTo = await this.getConnectedClients();
+ const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
+ const { clientIdentity, clientIdentity: { endpointId }, onUnsubscribeHandlerId } = otherClientState;
+ if (endpointId !== removingClientIdentity.endpointId && onUnsubscribeHandlerId) {
+ await this.provider.dispatch(clientIdentity, onUnsubscribeHandlerId, contextType);
+ }
+ });
+ try {
+ await Promise.all(dispatchPromises);
+ }
+ catch (error) {
+ console.error(`Problem when attempting to dispatch to onUnsubscribeHandlers. Error: ${error} Removing Client: ${handlerId}. uuid: ${removingClientIdentity.uuid}. name: ${removingClientIdentity.name}. endpointId: ${removingClientIdentity.endpointId}`);
+ throw new Error(error);
+ }
+ }
+ else {
+ console.warn(`Trying to remove a handler from a client that isn't mapped. handlerId: ${handlerId}. uuid: ${removingClientIdentity.uuid}. name: ${removingClientIdentity.name}. endpointId: ${removingClientIdentity.endpointId}.`);
+ }
+ }
+ nonStandardHandlerRemoved(payload, id) {
+ const { handlerId } = payload;
+ const clientState = this.getClientState(id);
+ if (clientState) {
+ if (clientState.onDisconnectHandlerId === handlerId) {
+ clientState.onDisconnectHandlerId = undefined;
+ }
+ else if (clientState.onAddContextListenerHandlerId === handlerId) {
+ clientState.onAddContextListenerHandlerId = undefined;
+ }
+ else if (clientState.onUnsubscribeHandlerId === handlerId) {
+ clientState.onUnsubscribeHandlerId = undefined;
+ }
+ }
+ else {
+ console.warn(`Trying to remove a handler from a client that isn't mapped. handlerId: ${handlerId}. clientIdentity: ${id}`);
+ }
+ }
+ onAddContextHandlerAdded(payload, senderClientIdentity) {
+ const clientState = this.getClientState(senderClientIdentity);
+ const { handlerId } = payload;
+ if (!clientState) {
+ throw new Error(`Client with Identity: ${senderClientIdentity.uuid} ${senderClientIdentity.name}, tried to call onAddContextListener, is not connected to this Private Channel`);
+ }
+ clientState.onAddContextListenerHandlerId = handlerId;
+ // FDC3 Spec says that the added listener should fire for all previously-registered addContextListeners from the other client
+ Array.from(this.clients.values()).forEach((otherClientState) => {
+ if (otherClientState.clientIdentity.endpointId !== senderClientIdentity.endpointId) {
+ Array.from(otherClientState.handlerIdsByContextTypes.keys()).forEach((subscribedContextType) => {
+ this.provider.dispatch(senderClientIdentity, handlerId, subscribedContextType);
+ });
+ }
+ });
+ }
+ onDisconnectHandlerAdded(payload, id) {
+ const clientState = this.getClientState(id);
+ const { handlerId } = payload;
+ if (!clientState) {
+ throw new Error(`Client with Identity: ${id.uuid} ${id.name}, tried to call onDisconnect, is not connected to this Private Channel`);
+ }
+ clientState.onDisconnectHandlerId = handlerId;
+ }
+ onUnsubscribeHandlerAdded(payload, id) {
+ const clientState = this.getClientState(id);
+ const { handlerId } = payload;
+ if (!clientState) {
+ throw new Error(`Client with Identity: ${id.uuid} ${id.name}, tried to call onUnsubscribe, is not connected to this Private Channel`);
+ }
+ clientState.onUnsubscribeHandlerId = handlerId;
+ }
+ removeClient(disconnectingClientIdentity) {
+ const disconnectingClientState = this.getClientState(disconnectingClientIdentity);
+ if (!disconnectingClientState) {
+ throw new Error(`Client with Identity: ${disconnectingClientIdentity.uuid} ${disconnectingClientIdentity.name}, tried to call disconnect, is not connected to this Private Channel`);
+ }
+ disconnectingClientState.handlerIdsByContextTypes.clear();
+ this.clients.delete(disconnectingClientIdentity.endpointId);
+ }
+ async fireOnDisconnectForOtherClients(disconnectingClientIdentity) {
+ // TODO: call onDisconnect Handler of the other client only.
+ // CURRENTLY, just calling the onDisconnect handler for all the other clients. Once we limit it to just one other client, we can eliminate all the iteration code.
+ const { endpointId } = disconnectingClientIdentity;
+ // getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
+ // so we need to ensure we don't dispatch to any disconnected client
+ // TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
+ const clientsToDispatchTo = await this.getConnectedClients();
+ const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
+ const { clientIdentity: { endpointId: otherClientEndpointId }, onDisconnectHandlerId } = otherClientState;
+ if (otherClientEndpointId !== endpointId && onDisconnectHandlerId) {
+ await this.provider.dispatch(otherClientState.clientIdentity, onDisconnectHandlerId);
+ }
+ });
+ try {
+ await Promise.all(dispatchPromises);
+ }
+ catch (error) {
+ console.error(`Problem when attempting to dispatch to onDisconnectHandlers. Error: ${error} Disconnecting Client: uuid: ${disconnectingClientIdentity.uuid}. name: ${disconnectingClientIdentity.name}. endpointId: ${disconnectingClientIdentity.endpointId}`);
+ throw new Error(error);
+ }
+ }
+ async unsubscribeAll(clientIdentity) {
+ const { endpointId } = clientIdentity;
+ const state = this.clients.get(endpointId);
+ if (state) {
+ const contextTypeHandlerIds = Array.from(state.handlerIdsByContextTypes.values()).flat();
+ const globalHandlerId = state.globalHandler;
+ if (contextTypeHandlerIds.length > 0) {
+ const unsubPromises = contextTypeHandlerIds.map(async (handlerId) => {
+ return this.contextHandlerRemoved({ handlerId }, clientIdentity);
+ });
+ try {
+ await Promise.all(unsubPromises);
+ }
+ catch (error) {
+ console.error(error.message);
+ }
+ }
+ if (globalHandlerId) {
+ try {
+ await this.contextHandlerRemoved({ handlerId: globalHandlerId }, clientIdentity);
+ }
+ catch (error) {
+ console.error(error.message);
+ }
+ }
+ }
+ }
+ async handleClientDisconnecting(disconnectingClientIdentity) {
+ await this.unsubscribeAll(disconnectingClientIdentity);
+ this.removeClient(disconnectingClientIdentity);
+ await this.fireOnDisconnectForOtherClients(disconnectingClientIdentity);
+ }
+ registerNewClient(clientIdentity) {
+ if (!this.clients.has(clientIdentity.endpointId)) {
+ const clientSubscriptionState = {
+ clientIdentity,
+ handlerIdsByContextTypes: new Map(),
+ globalHandler: undefined,
+ onAddContextListenerHandlerId: undefined,
+ onUnsubscribeHandlerId: undefined,
+ onDisconnectHandlerId: undefined
+ };
+ this.clients.set(clientIdentity.endpointId, clientSubscriptionState);
+ }
+ }
+ async getConnectedClients() {
+ const allClientInfo = await this.provider.getAllClientInfo();
+ return Array.from(this.clients.values()).filter((clientState) => {
+ const { uuid, name } = clientState.clientIdentity;
+ return allClientInfo.some((clientInfo) => {
+ return name === clientInfo.name && uuid === clientInfo.uuid;
+ });
+ });
+ }
+ static init(channelProvider, id) {
+ return new PrivateChannelProvider(channelProvider, id);
+ }
+ };
+ PrivateChannelProvider.PrivateChannelProvider = PrivateChannelProvider$1;
+ return PrivateChannelProvider;
+}
+
+var hasRequiredInteropBroker;
+
+function requireInteropBroker () {
+ if (hasRequiredInteropBroker) return InteropBroker;
+ hasRequiredInteropBroker = 1;
+ Object.defineProperty(InteropBroker, "__esModule", { value: true });
+ InteropBroker.InteropBroker = void 0;
+ const base_1 = base;
+ const SessionContextGroupBroker_1 = requireSessionContextGroupBroker();
+ const utils_1 = utils$1;
+ const lodash_1 = require$$3;
+ const PrivateChannelProvider_1 = requirePrivateChannelProvider();
+ let contextGroups = [
+ {
+ id: 'green',
+ displayMetadata: {
+ color: '#00CC88',
+ name: 'green'
+ }
+ },
+ {
+ id: 'purple',
+ displayMetadata: {
+ color: '#8C61FF',
+ name: 'purple'
+ }
+ },
+ {
+ id: 'orange',
+ displayMetadata: {
+ color: '#FF8C4C',
+ name: 'orange'
+ }
+ },
+ {
+ id: 'red',
+ displayMetadata: {
+ color: '#FF5E60',
+ name: 'red'
+ }
+ },
+ {
+ id: 'pink',
+ displayMetadata: {
+ color: '#FF8FB8',
+ name: 'pink'
+ }
+ },
+ {
+ id: 'yellow',
+ displayMetadata: {
+ color: '#E9FF8F',
+ name: 'yellow'
+ }
+ }
+ ];
+ /**
+ * {@link https://developers.openfin.co/of-docs/docs/enable-color-linking}
+ *
+ * The Interop Broker is responsible for keeping track of the Interop state of the Platform, and for directing messages to the proper locations.
+ *
+ * @remarks This class contains some types related to FDC3 that are specific to OpenFin. {@link https://developers.openfin.co/of-docs/docs/fdc3-support-in-openfin OpenFin's FDC3 support} is forward- and backward-compatible.
+ * Standard types for {@link https://fdc3.finos.org/ FDC3} do not appear in OpenFin’s API documentation, to avoid duplication.
+ *
+ * ---
+ *
+ * There are 2 ways to inject custom functionality into the Interop Broker:
+ *
+ * **1. Configuration**
+ *
+ * At the moment, you can configure the default context groups for the Interop Broker without having to override it. To do so, include the `interopBrokerConfiguration` `contextGroups` option in your `platform` options in your manifest. This is the preferred method.
+ * ```js
+ * {
+ * "runtime": {
+ * "arguments": "--v=1 --inspect",
+ * "version": "alpha-v19"
+ * },
+ * "platform": {
+ * "uuid": "platform_customization_local",
+ * "applicationIcon": "https://openfin.github.io/golden-prototype/favicon.ico",
+ * "autoShow": false,
+ * "providerUrl": "http://localhost:5555/provider.html",
+ * "interopBrokerConfiguration": {
+ * "contextGroups": [
+ * {
+ * "id": "green",
+ * "displayMetadata": {
+ * "color": "#00CC88",
+ * "name": "green"
+ * }
+ * },
+ * {
+ * "id": "purple",
+ * "displayMetadata": {
+ * "color": "#8C61FF",
+ * "name": "purple"
+ * }
+ * },
+ * ]
+ * }
+ * }
+ * }
+ * ```
+ *
+ * By default the Interop Broker logs all actions to the console. You can disable this by using the logging option in `interopBrokerConfiguration`:
+ * ```js
+ * {
+ * "runtime": {
+ * "arguments": "--v=1 --inspect",
+ * "version": "alpha-v19"
+ * },
+ * "platform": {
+ * "uuid": "platform_customization_local",
+ * "applicationIcon": "https://openfin.github.io/golden-prototype/favicon.ico",
+ * "autoShow": false,
+ * "providerUrl": "http://localhost:5555/provider.html",
+ * "interopBrokerConfiguration": {
+ * "logging": {
+ * "beforeAction": {
+ * "enabled": false
+ * },
+ * "afterAction": {
+ * "enabled": false
+ * }
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * ---
+ * **2. Overriding**
+ *
+ * Similarly to how {@link https://developers.openfin.co/docs/platform-customization#section-customizing-platform-behavior Platform Overriding} works, you can override functions in the Interop Broker in `fin.Platform.init`. An example of that is shown below. Overriding `isConnectionAuthorized` and `isActionAuthorized` will allow you to control allowed connections and allowed actions.
+ *
+ * However, if there is custom functionality you wish to include in the Interop Broker, please let us know. We would like to provide better configuration options so that you don't have to continually maintain your own override code.
+ *
+ * ```js
+ * fin.Platform.init({
+ * overrideCallback: async (Provider) => {
+ * class Override extends Provider {
+ * async getSnapshot() {
+ * console.log('before getSnapshot')
+ * const snapshot = await super.getSnapshot();
+ * console.log('after getSnapshot')
+ * return snapshot;
+ * }
+ *
+ * async applySnapshot({ snapshot, options }) {
+ * console.log('before applySnapshot')
+ * const originalPromise = super.applySnapshot({ snapshot, options });
+ * console.log('after applySnapshot')
+ *
+ * return originalPromise;
+ * }
+ * };
+ * return new Override();
+ * },
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async joinContextGroup(channelName = 'default', target) {
+ * console.log('before super joinContextGroup')
+ * super.joinContextGroup(channelName, target);
+ * console.log('after super joinContextGroup')
+ * }
+ * }
+ *
+ * return new Override();
+ * }
+ * });
+ * ```
+ *
+ * ---
+ *
+ */
+ let InteropBroker$1 = class InteropBroker extends base_1.Base {
+ /**
+ * @internal
+ */
+ constructor(wire, getProvider, options) {
+ // Tip from Pierre and Michael from the overrideCheck work: Don't use bound methods for overrideable InteropBroker functions.
+ super(wire);
+ this.getProvider = getProvider;
+ this.interopClients = new Map();
+ this.contextGroupsById = new Map();
+ if (options?.contextGroups) {
+ contextGroups = options.contextGroups;
+ }
+ if (options?.logging) {
+ this.logging = options.logging;
+ }
+ this.intentClientMap = new Map();
+ this.lastContextMap = new Map();
+ this.sessionContextGroupMap = new Map();
+ this.setContextGroupMap();
+ this.setupChannelProvider();
+ }
+ static createClosedConstructor(...args) {
+ return class OverrideableBroker extends InteropBroker {
+ constructor(...unused) {
+ if (unused.length) {
+ const [_ignore1, ignore2, opts] = unused;
+ if (opts && typeof opts === 'object' && !(0, lodash_1.isEqual)(opts, args[2])) {
+ // eslint-disable-next-line no-console
+ console.warn('You have modified the parameters of the InteropOverride constructor. This behavior is deprecated and will be removed in a future version. You can modify these options in your manifest. Please consult our Interop docs for guidance on migrating to the new override scheme.');
+ super(args[0], args[1], opts);
+ return;
+ }
+ // eslint-disable-next-line no-console
+ console.warn('You are attempting to pass arguments to the InteropOverride constructor. This is not necessary, and these passed arguments will be ignored. You are likely using an older InteropBroker override scheme. Please consult our Interop docs for guidance on migrating to the new override scheme.');
+ }
+ super(...args);
+ }
+ };
+ }
+ /*
+ Client API
+ */
+ /**
+ * @REMOVED
+ * SetContextOptions interface
+ * @typedef { object } SetContextOptions
+ * @property { Context } {context} - New context to set.
+ */
+ /**
+ * @REMOVED
+ * GetContextOptions interface
+ * @typedef { object } GetContextOptions
+ * @property { string } [contextType] - Context Type
+ */
+ // TODO: extract inline type and do proper comments
+ /**
+ * @REMOVED
+ * JoinContextGroupOptions interface
+ * @typedef { object } JoinContextGroupOptions
+ * @property { string } contextGroupId - Id of the context group.
+ * @property { Identity | ClientIdentity } [target] - Identity of the entity you wish to join to a context group.
+ */
+ /**
+ * @REMOVED
+ * AddClientToContextGroupOptions interface
+ * @typedef { object } AddClientToContextGroupOptions
+ * @property { string } contextGroupId - Name of the context group.
+ */
+ /**
+ * @REMOVED
+ * RemoveFromContextGroupOptions interface
+ * @typedef { object } RemoveFromContextGroupOptions
+ * @property { Identity | ClientIdentity } target - Identity of the entity you wish to join to a context group.
+ */
+ /**
+ * @REMOVED
+ * GetInfoForContextGroupOptions interface
+ * @typedef { object } GetInfoForContextGroupOptions
+ * @property { string } contextGroupId - Name of the context group to get info for.
+ */
+ /**
+ * @REMOVED
+ * GetAllClientsInContextGroupOptions interface
+ * @typedef { object } GetAllClientsInContextGroupOptions
+ * @property { string } contextGroupId - Name of the context group to get info for.
+ */
+ /**
+ * @PORTED
+ * InfoForIntentOptions interface
+ * @typedef { object } InfoForIntentOptions
+ * @property { string } name Name of the intent to get info for.
+ * @property { Context } [context] Optional context.
+ */
+ /**
+ * Sets a context for the context group of the incoming current entity.
+ * @param setContextOptions - New context to set.
+ * @param clientIdentity - Identity of the client sender.
+ *
+ */
+ setContext({ context }, clientIdentity) {
+ this.wire.sendAction('interop-broker-set-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const clientState = this.getClientState(clientIdentity);
+ if (clientState && clientState.contextGroupId) {
+ const { contextGroupId } = clientState;
+ if (!this.contextGroupsById.has(contextGroupId)) {
+ // Theoretically not possible.
+ throw new Error(`Client has a context group that isn't in the context group mapping: ${contextGroupId}.`);
+ }
+ const contextIntegrityCheckResult = InteropBroker.checkContextIntegrity(context);
+ if (contextIntegrityCheckResult.isValid === false) {
+ throw new Error(`Failed to set Context - bad Context. Reason: ${contextIntegrityCheckResult.reason}. Context: ${JSON.stringify(context)}`);
+ }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const contextGroupState = this.contextGroupsById.get(contextGroupId);
+ const broadcastedContextType = context.type;
+ contextGroupState.set(broadcastedContextType, context);
+ this.lastContextMap.set(contextGroupId, broadcastedContextType);
+ const clientsInSameContextGroup = Array.from(this.interopClients.values()).filter((connectedClient) => connectedClient.contextGroupId === contextGroupId);
+ clientsInSameContextGroup.forEach((client) => {
+ for (const [, handlerInfo] of client.contextHandlers) {
+ if (InteropBroker.isContextTypeCompatible(broadcastedContextType, handlerInfo.contextType)) {
+ this.invokeContextHandler(client.clientIdentity, handlerInfo.handlerId, context);
+ }
+ }
+ });
+ }
+ else if (clientState) {
+ // Client has not joined any context group behavior.
+ throw new Error('You must join a context group before you can set context.');
+ }
+ else {
+ // This shouldn't get hit.
+ throw new Error(`Client with Identity: ${clientIdentity.uuid} ${clientIdentity.name} not in Client State Map`);
+ }
+ }
+ /**
+ * Get current context for a client subscribed to a Context Group.
+ *
+ * @remarks It takes an optional Context Type argument and returns the last context of that type.
+ *
+ * @param getContextOptions - Options for getting context
+ * @param clientIdentity - Identity of the client sender.
+ *
+ */
+ getCurrentContext(getCurrentContextOptions, clientIdentity) {
+ this.wire.sendAction('interop-broker-get-current-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const clientState = this.getClientState(clientIdentity);
+ if (!clientState?.contextGroupId) {
+ throw new Error('You must be a member of a context group to call getCurrentContext');
+ }
+ const { contextGroupId } = clientState;
+ const contextGroupState = this.contextGroupsById.get(contextGroupId);
+ const lastContextType = this.lastContextMap.get(contextGroupId);
+ const contextType = getCurrentContextOptions?.contextType ?? lastContextType;
+ return contextGroupState && contextType ? contextGroupState.get(contextType) : undefined;
+ }
+ /*
+ Platform Window APIs
+ */
+ // joinContextGroup and addClientToContextGroup are separate functions here, for easier overrides and separation of concerns.
+ // joinContextGroup checks all connections for matching identities, in case we have multiple connection from an entity.
+ /**
+ * Join all connections at the given identity (or just one if endpointId provided) to context group `contextGroupId`.
+ * If no target is specified, it adds the sender to the context group.
+ * joinContextGroup is responsible for checking connections at the incoming identity. It calls {@link InteropBroker#addClientToContextGroup InteropBroker.addClientToContextGroup} to actually group the client.
+ * Used by Platform Windows.
+ *
+ * @param joinContextGroupOptions - Id of the Context Group and identity of the entity to join to the group.
+ * @param senderIdentity - Identity of the client sender.
+ */
+ async joinContextGroup({ contextGroupId, target }, senderIdentity) {
+ this.wire.sendAction('interop-broker-join-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ if (this.sessionContextGroupMap.has(contextGroupId)) {
+ throw new Error(utils_1.BROKER_ERRORS.joinSessionContextGroupWithJoinContextGroup);
+ }
+ if (target) {
+ // If an endpointId is provided, use that. This will likely be used by external adapters.
+ if (InteropBroker.hasEndpointId(target)) {
+ await this.addClientToContextGroup({ contextGroupId }, target);
+ }
+ // Sanity check here in case a single app has multiple connections
+ try {
+ const allConnections = this.channel.connections.filter((x) => x.uuid === target.uuid && x.name === target.name);
+ if (!allConnections.length) {
+ throw new Error(`Given Identity ${target.uuid} ${target.name} is not connected to the Interop Broker.`);
+ }
+ if (allConnections.length > 1) {
+ // Should figure out how we want to handle this situation. In the meantime, just change context group for all connections.
+ console.warn(`More than one connection found for identity ${target.uuid} ${target.name}`);
+ }
+ const promises = [];
+ for (const connection of allConnections) {
+ promises.push(this.addClientToContextGroup({ contextGroupId }, connection));
+ }
+ await Promise.all(promises);
+ }
+ catch (error) {
+ throw new Error(error);
+ }
+ }
+ else {
+ // No target provided, add the sender to the context group.
+ await this.addClientToContextGroup({ contextGroupId }, senderIdentity);
+ }
+ }
+ // addClientToContextGroup does the actual addition of the client to the Context Group
+ /**
+ * Helper function for {@link InteropBroker#joinContextGroup InteropBroker.joinContextGroup}. Does the work of actually adding the client to the Context Group.
+ * Used by Platform Windows.
+ *
+ * @param addClientToContextGroupOptions - Contains the contextGroupId
+ * @param clientIdentity - Identity of the client sender.
+ */
+ async addClientToContextGroup({ contextGroupId }, clientIdentity) {
+ this.wire.sendAction('interop-broker-add-client-to-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const clientSubscriptionState = this.getClientState(clientIdentity);
+ if (!clientSubscriptionState) {
+ throw new Error(`Client with Identity: ${clientIdentity.uuid} ${clientIdentity.name} not in Client State Map`);
+ }
+ if (!this.getContextGroups().find((contextGroupInfo) => contextGroupInfo.id === contextGroupId)) {
+ throw new Error(`Attempting to join a context group that does not exist: ${contextGroupId}. You may only join existing context groups.`);
+ }
+ const oldContextGroupId = clientSubscriptionState.contextGroupId;
+ if (oldContextGroupId !== contextGroupId) {
+ clientSubscriptionState.contextGroupId = contextGroupId;
+ await this.setCurrentContextGroupInClientOptions(clientIdentity, contextGroupId);
+ const contextGroupMap = this.contextGroupsById.get(contextGroupId);
+ for (const [, handlerInfo] of clientSubscriptionState.contextHandlers) {
+ const { contextType, handlerId } = handlerInfo;
+ if (contextType === undefined) {
+ // Send this single handler all of the context, because it accepts all.
+ contextGroupMap.forEach((context, _) => {
+ this.invokeContextHandler(clientIdentity, handlerId, context);
+ });
+ }
+ else if (contextGroupMap.has(contextType)) {
+ const contextForType = contextGroupMap.get(contextType);
+ if (contextForType) {
+ this.invokeContextHandler(clientIdentity, handlerId, contextForType);
+ }
+ }
+ }
+ }
+ }
+ // Removes the target from its context group. Similar structure to joinContextGroup.
+ /**
+ * Removes the specified target from a context group.
+ * If no target is specified, it removes the sender from their context group.
+ * removeFromContextGroup is responsible for checking connections at the incoming identity.
+ *
+ * @remarks It calls {@link InteropBroker#removeClientFromContextGroup InteropBroker.removeClientFromContextGroup} to actually ungroup
+ * the client. Used by Platform Windows.
+ *
+ * @param removeFromContextGroupOptions - Contains the target identity to remove.
+ * @param senderIdentity - Identity of the client sender.
+ */
+ async removeFromContextGroup({ target }, senderIdentity) {
+ this.wire.sendAction('interop-broker-remove-from-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ if (target) {
+ // If an endpointId is provided, use that. This will likely be used by external adapters.
+ if (InteropBroker.hasEndpointId(target)) {
+ await this.removeClientFromContextGroup(target);
+ }
+ try {
+ // Sanity check here in case a single app has multiple connections
+ const allConnections = this.channel.connections.filter((x) => x.uuid === target.uuid && x.name === target.name);
+ if (!allConnections.length) {
+ throw new Error(`No connection found for given Identity ${target.uuid} ${target.name}`);
+ }
+ if (allConnections.length > 1) {
+ console.warn(`More than one connection found for identity ${target.uuid} ${target.name}`);
+ }
+ const promises = [];
+ for (const connection of allConnections) {
+ promises.push(this.removeClientFromContextGroup(connection));
+ }
+ await Promise.all(promises);
+ }
+ catch (error) {
+ throw new Error(error);
+ }
+ }
+ else {
+ // No target provided, remove the sender from the context group.
+ await this.removeClientFromContextGroup(senderIdentity);
+ }
+ }
+ // removeClientFromContextGroup does the actual remove of the client from the Context Group
+ /**
+ * Helper function for {@link InteropBroker#removeFromContextGroup InteropBroker.removeFromContextGroup}. Does the work of actually removing the client from the Context Group.
+ * Used by Platform Windows.
+ *
+ * @property { ClientIdentity } clientIdentity - Identity of the client sender.
+ */
+ async removeClientFromContextGroup(clientIdentity) {
+ this.wire.sendAction('interop-broker-remove-client-from-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const clientState = this.getClientState(clientIdentity);
+ if (clientState) {
+ clientState.contextGroupId = undefined;
+ }
+ await this.setCurrentContextGroupInClientOptions(clientIdentity, null);
+ }
+ // Used by platform windows to know what client groups the provider has declared. Also used internally to access context groups. Overrideable so that the platform developer can modify it.
+ /**
+ * Returns the Interop-Broker-defined context groups available for an entity to join. Because this function is used in the rest of the Interop Broker to fetch the Context Groups, overriding this allows you to customize the Context Groups for the Interop Broker. However, we recommend customizing the context groups through configuration instead.
+ * Used by Platform Windows.
+ *
+ */
+ // eslint-disable-next-line class-methods-use-this
+ getContextGroups() {
+ this.wire.sendAction('interop-broker-get-context-groups').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ // Create copy for immutability
+ return contextGroups.map((contextGroup) => {
+ return { ...contextGroup };
+ });
+ }
+ // Used to by platform windows to get display metadata for a context group.
+ /**
+ * Gets display info for a context group
+ *
+ * @remarks Used by Platform Windows.
+ *
+ * @param getInfoForContextGroupOptions - Contains contextGroupId, the context group you wish to get display info for.
+ *
+ */
+ getInfoForContextGroup({ contextGroupId }) {
+ this.wire.sendAction('interop-broker-get-info-for-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ return this.getContextGroups().find((contextGroup) => contextGroup.id === contextGroupId);
+ }
+ // Used by platform windows to get all clients for a context group.
+ /**
+ * Gets all clients for a context group.
+ *
+ * @remarks **This is primarily used for platform windows. Views within a platform should not have to use this API.**
+ * Returns the Interop-Broker-defined context groups available for an entity to join.
+ *
+ * @param getAllClientsInContextGroupOptions - Contains contextGroupId, the context group you wish to get clients for.
+ *
+ */
+ getAllClientsInContextGroup({ contextGroupId }) {
+ this.wire.sendAction('interop-broker-get-all-clients-in-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const clientsInContextGroup = Array.from(this.interopClients.values())
+ .filter((connectedClient) => connectedClient.contextGroupId === contextGroupId)
+ .map((subscriptionState) => {
+ return subscriptionState.clientIdentity;
+ });
+ return clientsInContextGroup;
+ }
+ /**
+ * Responsible for launching of applications that can handle a given intent, and delegation of intents to those applications.
+ * Must be overridden.
+ *
+ * @remarks To make this call FDC3-Compliant it would need to return an IntentResolution.
+ *
+ * ```js
+ * interface IntentResolution {
+ * source: TargetApp;
+ * // deprecated, not assignable from intent listeners
+ * data?: object;
+ * version: string;
+ * }
+ * ```
+ *
+ * More information on the IntentResolution type can be found in the [FDC3 documentation](https://fdc3.finos.org/docs/api/ref/IntentResolution).
+ *
+ * @param intent The combination of an action and a context that is passed to an application for resolution.
+ * @param clientIdentity Identity of the Client making the request.
+ *
+ * @example
+ * ```js
+ * // override call so we set intent target and create view that will handle it
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async handleFiredIntent(intent) {
+ * super.setIntentTarget(intent, { uuid: 'platform-uuid', name: 'intent-view' });
+ * const platform = fin.Platform.getCurrentSync();
+ * const win = fin.Window.wrapSync({ name: 'foo', uuid: 'platform-uuid' });
+ * const createdView = await platform.createView({ url: 'http://openfin.co', name: 'intent-view' }, win.identity);
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async handleFiredIntent(intent, clientIdentity // TODO(CORE-811): remove inline intersected type
+ ) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.raiseIntent', 'InteropBroker.handleFiredIntent', clientIdentity, 'interopClient.fireIntent');
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.fireIntent);
+ }
+ /**
+ * Should be called in {@link InteropBroker#handleFiredIntent InteropBroker.handleFiredIntent}.
+ * While handleFiredIntent is responsible for launching applications, setIntentTarget is used to tell the InteropBroker which application should receive the intent when it is ready.
+ * @param intent The combination of an action and a context that is passed to an application for resolution.
+ * @param target - Identity of the target that will handle the intent.
+ *
+ */
+ async setIntentTarget(intent, target) {
+ this.wire.sendAction('interop-broker-set-intent-target').catch((e) => {
+ // don't expose, this is only for api analytics purposes
+ });
+ const targetInfo = this.intentClientMap.get(target.name);
+ const handlerId = `intent-handler-${intent.name}`;
+ if (!targetInfo) {
+ this.intentClientMap.set(target.name, new Map());
+ const newHandlerInfoMap = this.intentClientMap.get(target.name);
+ if (newHandlerInfoMap) {
+ newHandlerInfoMap.set(handlerId, { isReady: false, pendingIntents: [intent] });
+ }
+ }
+ else {
+ const handlerInfo = targetInfo.get(handlerId);
+ if (!handlerInfo) {
+ targetInfo.set(handlerId, { isReady: false, pendingIntents: [intent] });
+ }
+ else {
+ handlerInfo.pendingIntents.push(intent);
+ if (handlerInfo.clientIdentity && handlerInfo.isReady) {
+ const { clientIdentity, pendingIntents } = handlerInfo;
+ try {
+ const intentToSend = pendingIntents[pendingIntents.length - 1];
+ await this.invokeIntentHandler(clientIdentity, handlerId, intentToSend);
+ handlerInfo.pendingIntents = [];
+ }
+ catch (error) {
+ console.error(`Error invoking intent handler for client ${clientIdentity.uuid}/${clientIdentity.name}/${clientIdentity.endpointId}`);
+ handlerInfo.isReady = false;
+ }
+ }
+ }
+ }
+ }
+ /**
+ * Responsible for returning information on a particular Intent.
+ *
+ * @remarks Whenever InteropClient.getInfoForIntent is called this function will fire. The options argument gives you
+ * access to the intent name and any optional context that was passed and clientIdentity is the identity of the client
+ * that made the call. Ideally here you would fetch the info for the intent and return it with the shape that the
+ * InteropClient.getInfoForIntent call is expecting.
+ *
+ * To make this call FDC3-Compliant it would need to return an App Intent:
+ *
+ * ```js
+ * // {
+ * // intent: { name: "StartChat", displayName: "Chat" },
+ * // apps: [{ name: "Skype" }, { name: "Symphony" }, { name: "Slack" }]
+ * // }
+ * ```
+ *
+ * More information on the AppIntent type can be found in the [FDC3 documentation](https://fdc3.finos.org/docs/api/ref/AppIntent).
+ *
+ * @param options
+ * @param clientIdentity Identity of the Client making the request.
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async handleInfoForIntent(options, clientIdentity) {
+ * // Your code goes here.
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async handleInfoForIntent(options, clientIdentity // TODO(CORE-811): remove inline intersected type
+ ) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.findIntent', 'InteropBroker.handleInfoForIntent', clientIdentity, 'interopClient.getInfoForIntent');
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.getInfoForIntent);
+ }
+ /**
+ * Responsible for returning information on which Intents are meant to handle a specific Context.
+ * Must be overridden.
+ *
+ * @remarks Responsible for returning information on which Intents are meant to handle a specific Context. Must be overridden.
+ *
+ * Whenever InteropClient.getInfoForIntentsByContext is called this function will fire. The context argument gives you access to the context that the client wants information on and clientIdentity is the identity of the client that made the call. Ideally here you would fetch the info for any intent that can handle and return it with the shape that the InteropClient.getInfoForIntentsByContext call is expecting.
+ *
+ * To make this call FDC3-Compliant it would need to return an array of AppIntents:
+ *
+ * ```js
+ * // [{
+ * // intent: { name: "StartCall", displayName: "Call" },
+ * // apps: [{ name: "Skype" }]
+ * // },
+ * // {
+ * // intent: { name: "StartChat", displayName: "Chat" },
+ * // apps: [{ name: "Skype" }, { name: "Symphony" }, { name: "Slack" }]
+ * // }];
+ * ```
+ *
+ * More information on the AppIntent type can be found in the [FDC3 documentation](https://fdc3.finos.org/docs/api/ref/AppIntent).
+ *
+ * @param context Data passed between entities and applications.
+ * @param clientIdentity Identity of the Client making the request.
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async handleInfoForIntentsByContext(context, clientIdentity) {
+ * // Your code goes here.
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async handleInfoForIntentsByContext(context, clientIdentity // TODO(CORE-811): remove inline intersected type
+ ) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.findIntentsByContext', 'InteropBroker.handleInfoForIntentsByContext', clientIdentity, 'interopClient.getInfoForIntentsByContext');
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.getInfoForIntentsByContext);
+ }
+ /**
+ * Responsible for resolving an Intent based on a specific Context.
+ * Must be overridden.
+ *
+ * @remarks Whenever InteropClient.fireIntentForContext is called this function will fire. The contextForIntent argument
+ * gives you access to the context that will be resolved to an intent. It also can optionally contain any metadata relevant
+ * to resolving it, like a specific app the client wants the context to be handled by. The clientIdentity is the identity
+ * of the client that made the call.
+ *
+ * To make this call FDC3-Compliant it would need to return an IntentResolution:
+ *
+ * ```js
+ * // {
+ * // intent: { name: "StartChat", displayName: "Chat" },
+ * // apps: [{ name: "Skype" }, { name: "Symphony" }, { name: "Slack" }]
+ * // }
+ * ```
+ *
+ * More information on the IntentResolution type can be found in the [FDC3 documentation](https://fdc3.finos.org/docs/api/ref/Metadata#intentresolution).
+ *
+ * @param contextForIntent Data passed between entities and applications.
+ * @param clientIdentity Identity of the Client making the request.
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async handleFiredIntentForContext(contextForIntent, clientIdentity) {
+ * // Your code goes here.
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async handleFiredIntentForContext(contextForIntent, clientIdentity) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.raiseIntentForContext', 'InteropBroker.handleFiredIntentForContext', clientIdentity, 'interopClient.fireIntentForContext');
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.fireIntentForContext);
+ }
+ /**
+ * Provides the identity of any Interop Client that disconnects from the Interop Broker. It is meant to be overriden.
+ * @param clientIdentity
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async clientDisconnected(clientIdentity) {
+ * const { uuid, name } = clientIdentity;
+ * console.log(`Client with identity ${uuid}/${name} has been disconnected`);
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async clientDisconnected(clientIdentity) {
+ // This function is called in channel.onDisconnection.
+ // It is meant to be overridden to inform when an Interop Client has been disconnected.
+ }
+ /**
+ * Responsible for resolving an fdc3.open call.
+ * Must be overridden.
+ * @param fdc3OpenOptions fdc3.open options
+ * @param clientIdentity Identity of the Client making the request.
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async fdc3HandleOpen({ app, context }, clientIdentity) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.open', 'InteropBroker.fdc3HandleOpen', clientIdentity);
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.fdc3Open);
+ }
+ /**
+ * Responsible for resolving the fdc3.findInstances call.
+ * Must be overridden
+ * @param app AppIdentifier that was passed to fdc3.findInstances
+ * @param clientIdentity Identity of the Client making the request.
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async fdc3HandleFindInstances(app, clientIdentity) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.open', 'InteropBroker.fdc3HandleFindInstances', clientIdentity);
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.fdc3FindInstances);
+ }
+ /**
+ * Responsible for resolving the fdc3.getAppMetadata call.
+ * Must be overridden
+ * @param app AppIdentifier that was passed to fdc3.getAppMetadata
+ * @param clientIdentity Identity of the Client making the request.
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async fdc3HandleGetAppMetadata(app, clientIdentity) {
+ const warning = (0, utils_1.generateOverrideWarning)('fdc3.getAppMetadata', 'InteropBroker.fdc3HandleGetAppMetadata', clientIdentity);
+ console.warn(warning);
+ throw new Error(utils_1.BROKER_ERRORS.fdc3GetAppMetadata);
+ }
+ /**
+ * This function is called by the Interop Broker whenever a Context handler would fire.
+ * For FDC3 2.0 you would need to override this function and add the contextMetadata as
+ * part of the Context object. Then would you need to call
+ * super.invokeContextHandler passing it this new Context object along with the clientIdentity and handlerId
+ * @param clientIdentity
+ * @param handlerId
+ * @param context
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async invokeContextHandler(clientIdentity, handlerId, context) {
+ * return super.invokeContextHandler(clientIdentity, handlerId, {
+ * ...context,
+ * contextMetadata: {
+ * source: {
+ * appId: 'openfin-app',
+ * instanceId: '3D54D456D9HT0'
+ * }
+ * }
+ * });
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ async invokeContextHandler(clientIdentity, handlerId, context) {
+ const provider = await this.getProvider();
+ try {
+ await provider.dispatch(clientIdentity, handlerId, context);
+ }
+ catch (error) {
+ console.error(`Error invoking context handler ${handlerId} for context type ${context.type} in client ${clientIdentity.uuid}/${clientIdentity.name}/${clientIdentity.endpointId}`, error);
+ }
+ }
+ /**
+ * This function is called by the Interop Broker whenever an Intent handler would fire.
+ * For FDC3 2.0 you would need to override this function and add the contextMetadata as
+ * part of the Context object inside the Intent object. Then would you need to call
+ * super.invokeIntentHandler passing it this new Intent object along with the clientIdentity and handlerId
+ * @param ClientIdentity
+ * @param handlerId
+ * @param context
+ *
+ * @example
+ * ```js
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker) => {
+ * class Override extends InteropBroker {
+ * async invokeIntentHandler(clientIdentity, handlerId, context) {
+ * const { context } = intent;
+ * return super.invokeIntentHandler(clientIdentity, handlerId, {
+ * ...intent,
+ * context: {
+ * ...context,
+ * contextMetadata: {
+ * source: {
+ * appId: 'openfin-app',
+ * instanceId: '3D54D456D9HT0'
+ * }
+ * }
+ * }
+ * });
+ * }
+ * }
+ * return new Override();
+ * }
+ * });
+ * ```
+ */
+ async invokeIntentHandler(clientIdentity, handlerId, intent) {
+ const provider = await this.getProvider();
+ await provider.dispatch(clientIdentity, handlerId, intent);
+ }
+ /**
+ * Responsible for resolving fdc3.getInfo for FDC3 2.0
+ * Would need to return the optionalFeatures and appMetadata for the {@link https://fdc3.finos.org/docs/api/ref/Metadata#implementationmetadata ImplementationMetadata}.
+ * Must be overridden.
+ * @param clientIdentity
+ *
+ */
+ // eslint-disable-next-line class-methods-use-this
+ async fdc3HandleGetInfo(payload, clientIdentity) {
+ const { fdc3Version } = payload;
+ return {
+ fdc3Version,
+ provider: 'OpenFin',
+ providerVersion: await this.fin.System.getVersion(),
+ optionalFeatures: {
+ OriginatingAppMetadata: false,
+ UserChannelMembershipAPIs: true
+ },
+ appMetadata: {
+ appId: '',
+ instanceId: ''
+ }
+ };
+ }
+ /**
+ * Returns an array of info for each Interop Client connected to the Interop Broker.
+ *
+ * FDC3 2.0: Use the endpointId in the ClientInfo as the instanceId when generating
+ * an AppIdentifier.
+ *
+ * @remarks FDC3 2.0 Note: When needing an instanceId to generate an AppIdentifier use this call to
+ * get the endpointId and use it as the instanceId. In the Example below we override handleFiredIntent
+ * and then call super.getAllClientInfo to generate the AppIdentifier for the IntentResolution.
+ *
+ *
+ * @example
+ * ```js
+ * // FDC3 2.0 Example:
+ * fin.Platform.init({
+ * interopOverride: async (InteropBroker, ...args) => {
+ * class Override extends InteropBroker {
+ * async handleFiredIntent(intent) {
+ * super.setIntentTarget(intent, { uuid: 'platform-uuid', name: 'intent-view' });
+ * const platform = fin.Platform.getCurrentSync();
+ * const win = fin.Window.wrapSync({ name: 'foo', uuid: 'platform-uuid' });
+ * const createdView = await platform.createView({ url: 'http://openfin.co', name: 'intent-view' }, win.identity);
+ *
+ * const allClientInfo = await super.getAllClientInfo();
+ *
+ * const infoForTarget = allClientInfo.find((clientInfo) => {
+ * return clientInfo.uuid === 'platform-uuid' && clientInfo.name === 'intent-view';
+ * });
+ *
+ * const source = {
+ * appId: 'intent-view',
+ * instanceId: infoForTarget.endpointId
+ * }
+ *
+ * return {
+ * source,
+ * intent: intent.name
+ * }
+ *
+ * }
+ * }
+ * return new Override(...args);
+ * }
+ * });
+ * ```
+ */
+ async getAllClientInfo() {
+ const provider = await this.getProvider();
+ return provider.getAllClientInfo();
+ }
+ /*
+ Snapshot APIs
+ */
+ // Used to save interop broker state in snapshots
+ decorateSnapshot(snapshot) {
+ return { ...snapshot, interopSnapshotDetails: { contextGroupStates: this.getContextGroupStates() } };
+ }
+ // Used to restore interop broker state in snapshots.
+ applySnapshot(snapshot, options) {
+ const contextGroupStates = snapshot?.interopSnapshotDetails?.contextGroupStates;
+ if (contextGroupStates) {
+ if (!options?.closeExistingWindows) {
+ this.updateExistingClients(contextGroupStates);
+ }
+ this.rehydrateContextGroupStates(contextGroupStates);
+ }
+ }
+ updateExistingClients(contextGroupStates) {
+ const clients = this.interopClients;
+ clients.forEach((subState) => {
+ const { clientIdentity, contextGroupId, contextHandlers } = subState;
+ if (contextGroupId) {
+ const groupContexts = contextGroupStates[contextGroupId];
+ for (const [, context] of Object.entries(groupContexts)) {
+ contextHandlers.forEach((contextHandler) => {
+ const { handlerId, contextType } = contextHandler;
+ if (InteropBroker.isContextTypeCompatible(context.type, contextType)) {
+ this.invokeContextHandler(clientIdentity, handlerId, context);
+ }
+ });
+ }
+ }
+ });
+ }
+ // Used to store context group state in snapshots
+ getContextGroupStates() {
+ return InteropBroker.toObject(this.contextGroupsById);
+ }
+ // Used to rehydrate the context state from a snapshot
+ rehydrateContextGroupStates(incomingContextGroupStates) {
+ const contextGroupStates = Object.entries(incomingContextGroupStates);
+ for (const [contextGroupId, contexts] of contextGroupStates) {
+ const contextObjects = Object.entries(contexts);
+ for (const [contextType, context] of contextObjects) {
+ if (this.contextGroupsById.has(contextGroupId)) {
+ const currentContextGroupState = this.contextGroupsById.get(contextGroupId);
+ currentContextGroupState.set(contextType, context);
+ }
+ else {
+ // This logic will change when dynamic context group creation comes in.
+ console.warn(`Attempting to set a context group that isn't in the context group mapping. Skipping context group rehydration for: ${contextGroupId}`);
+ }
+ }
+ }
+ }
+ /*
+ Internal Context Handler APIs
+ */
+ // Used to give context to a client that has registered their context handler
+ contextHandlerRegistered({ contextType, handlerId }, clientIdentity) {
+ const handlerInfo = { contextType, handlerId };
+ const clientState = this.getClientState(clientIdentity);
+ clientState?.contextHandlers.set(handlerId, handlerInfo);
+ if (clientState && clientState.contextGroupId) {
+ const { contextGroupId } = clientState;
+ const contextGroupMap = this.contextGroupsById.get(contextGroupId);
+ if (contextType === undefined) {
+ // Send this single handler all of the context, because it accepts all.
+ contextGroupMap.forEach((context, _) => {
+ this.invokeContextHandler(clientIdentity, handlerId, context);
+ });
+ }
+ else if (contextGroupMap.has(contextType)) {
+ const contextForType = contextGroupMap.get(contextType);
+ if (contextForType) {
+ this.invokeContextHandler(clientIdentity, handlerId, contextForType);
+ }
+ }
+ }
+ }
+ // eslint-disable-next-line class-methods-use-this
+ async intentHandlerRegistered(payload, clientIdentity) {
+ const { handlerId } = payload;
+ const clientIntentInfo = this.intentClientMap.get(clientIdentity.name);
+ const handlerInfo = clientIntentInfo?.get(handlerId);
+ if (!clientIntentInfo) {
+ this.intentClientMap.set(clientIdentity.name, new Map());
+ const newHandlerInfoMap = this.intentClientMap.get(clientIdentity.name);
+ if (newHandlerInfoMap) {
+ newHandlerInfoMap.set(handlerId, { isReady: true, pendingIntents: [], clientIdentity });
+ }
+ }
+ else if (!handlerInfo) {
+ clientIntentInfo.set(handlerId, { isReady: true, pendingIntents: [], clientIdentity });
+ }
+ else {
+ const { pendingIntents } = handlerInfo;
+ handlerInfo.clientIdentity = clientIdentity;
+ handlerInfo.isReady = true;
+ try {
+ if (pendingIntents.length > 0) {
+ const intentToSend = pendingIntents[pendingIntents.length - 1];
+ await this.invokeIntentHandler(clientIdentity, handlerId, intentToSend);
+ handlerInfo.pendingIntents = [];
+ }
+ }
+ catch (error) {
+ console.error(`Error invoking intent handler: ${handlerId} for client ${clientIdentity.uuid}/${clientIdentity.name}/${clientIdentity.endpointId}`);
+ }
+ }
+ }
+ // Used to remove a context handler for a client
+ removeContextHandler({ handlerId }, clientIdentity) {
+ const clientState = this.getClientState(clientIdentity);
+ if (clientState) {
+ clientState.contextHandlers.delete(handlerId);
+ }
+ }
+ handleJoinSessionContextGroup({ sessionContextGroupId }, clientIdentity) {
+ try {
+ if (!sessionContextGroupId) {
+ throw new Error('Failed to join session context group: must specify group id.');
+ }
+ const sessionContextGroup = this.sessionContextGroupMap.get(sessionContextGroupId);
+ if (sessionContextGroup) {
+ sessionContextGroup.registerNewClient(clientIdentity);
+ }
+ else {
+ const newSessionContextGroupBroker = new SessionContextGroupBroker_1.default(this.channel, sessionContextGroupId);
+ newSessionContextGroupBroker.registerNewClient(clientIdentity);
+ this.sessionContextGroupMap.set(sessionContextGroupId, newSessionContextGroupBroker);
+ }
+ return { hasConflict: this.contextGroupsById.has(sessionContextGroupId) };
+ }
+ catch (error) {
+ throw new Error(error);
+ }
+ }
+ /*
+ Internal Utilties
+ */
+ // Getter for interop info for a client.
+ getClientState(id) {
+ return this.interopClients.get(id.endpointId);
+ }
+ // Util for getContextGroupStates. Serializes the contextGroupStates object so we can store it.
+ static toObject(map) {
+ const objectFromMap = Object.fromEntries(map);
+ const newObject = {};
+ Object.entries(objectFromMap).forEach(([contextGroupId, contextMap]) => {
+ const newContextObject = Object.fromEntries(contextMap);
+ newObject[contextGroupId] = newContextObject;
+ });
+ return newObject;
+ }
+ static checkContextIntegrity(context) {
+ if (!context) {
+ return { isValid: false, reason: 'No context supplied' };
+ }
+ if (typeof context !== 'object') {
+ return { isValid: false, reason: 'Context must be an Object' };
+ }
+ if (!context.type) {
+ return { isValid: false, reason: 'Context must have a type property' };
+ }
+ if (context.id && typeof context.id !== 'object') {
+ return {
+ isValid: false,
+ reason: 'Context id must be an Object populated with key-value identifiers (if set)'
+ };
+ }
+ if (context.id) {
+ const { id } = context;
+ const keys = Object.keys(id);
+ let foundBadIdentifier = false;
+ if (!keys.length) {
+ return { isValid: false, reason: 'Context id must have at least one key-value identifier' };
+ }
+ keys.forEach((key) => {
+ if (typeof key !== 'string' || typeof id[key] !== 'string') {
+ foundBadIdentifier = true;
+ }
+ });
+ if (foundBadIdentifier) {
+ return { isValid: false, reason: 'Context id key-value identifiers must be of type string' };
+ }
+ }
+ if (context.name && typeof context.name !== 'string') {
+ return { isValid: false, reason: 'Context name must be of string type (if set)' };
+ }
+ return { isValid: true };
+ }
+ // Util to check a client identity.
+ static hasEndpointId(target) {
+ return target.endpointId !== undefined;
+ }
+ // Util to check if we should send a context to a handler.
+ static isContextTypeCompatible(contextType, registeredContextType) {
+ return typeof registeredContextType === 'undefined' || contextType === registeredContextType;
+ }
+ // Setup function for state mapping
+ setContextGroupMap() {
+ // This way, if a user overrides this.getContextGroups, it's reflected in the contextGroupMapping.
+ for (const contextGroupInfo of this.getContextGroups()) {
+ this.contextGroupsById.set(contextGroupInfo.id, new Map());
+ }
+ }
+ async setCurrentContextGroupInClientOptions(clientIdentity, contextGroupId) {
+ const entityInfo = await this.fin.System.getEntityInfo(clientIdentity.uuid, clientIdentity.name);
+ let entity;
+ if (entityInfo.entityType === 'view') {
+ entity = await this.fin.View.wrap(clientIdentity);
+ }
+ else if (entityInfo.entityType === 'window') {
+ entity = await this.fin.Window.wrap(clientIdentity);
+ }
+ if (entity) {
+ await entity.updateOptions({
+ interop: {
+ currentContextGroup: contextGroupId
+ }
+ });
+ }
+ else {
+ console.warn(`Setting Current Context Group: Entity with identity ${clientIdentity.uuid}, ${clientIdentity.name} is not a window or view. It is a ${entityInfo.entityType} instead.`);
+ }
+ }
+ async setupChannelProvider() {
+ try {
+ const channel = await this.getProvider();
+ this.channel = channel;
+ this.wireChannel(channel);
+ }
+ catch (error) {
+ throw new Error(`Error setting up Interop Broker Channel Provider: ${error}`);
+ }
+ }
+ // Setup Channel Connection Logic
+ wireChannel(channel) {
+ channel.onConnection(async (clientIdentity, // TODO(CORE-811): remove inline intersected type
+ payload) => {
+ if (!(await this.isConnectionAuthorized(clientIdentity, payload))) {
+ throw new Error(`Connection not authorized for ${clientIdentity.uuid}, ${clientIdentity.name}`);
+ }
+ if (!clientIdentity.endpointId) {
+ throw new Error('Version too old to be compatible with Interop. Please upgrade your runtime to a more recent version.');
+ }
+ const clientSubscriptionState = {
+ contextGroupId: undefined,
+ contextHandlers: new Map(),
+ clientIdentity
+ };
+ // Only allow the client to join a contextGroup that actually exists.
+ if (payload?.currentContextGroup && this.contextGroupsById.has(payload.currentContextGroup)) {
+ clientSubscriptionState.contextGroupId = payload?.currentContextGroup;
+ }
+ this.interopClients.set(clientIdentity.endpointId, clientSubscriptionState);
+ });
+ channel.onDisconnection((clientIdentity) => {
+ this.interopClients.delete(clientIdentity.endpointId);
+ const targetInfo = this.intentClientMap.get(clientIdentity.name);
+ if (targetInfo && clientIdentity.uuid === this.fin.me.uuid) {
+ targetInfo.forEach((handler) => {
+ handler.isReady = false;
+ });
+ }
+ this.sessionContextGroupMap.forEach((sessionContextGroup) => {
+ sessionContextGroup.onDisconnection(clientIdentity);
+ });
+ this.clientDisconnected(clientIdentity);
+ });
+ channel.beforeAction(async (action, payload, clientIdentity) => {
+ if (!(await this.isActionAuthorized(action, payload, clientIdentity))) {
+ throw new Error(`Action (${action}) not authorized for ${clientIdentity.uuid}, ${clientIdentity.name}`);
+ }
+ if (this.logging?.beforeAction?.enabled) {
+ console.log(action, payload, clientIdentity);
+ }
+ });
+ channel.afterAction((action, payload, clientIdentity) => {
+ if (this.logging?.afterAction?.enabled) {
+ console.log(action, payload, clientIdentity);
+ }
+ });
+ // Client functions
+ channel.register('setContext', this.setContext.bind(this));
+ channel.register('fireIntent', this.handleFiredIntent.bind(this));
+ channel.register('getCurrentContext', this.getCurrentContext.bind(this));
+ channel.register('getInfoForIntent', this.handleInfoForIntent.bind(this));
+ channel.register('getInfoForIntentsByContext', this.handleInfoForIntentsByContext.bind(this));
+ channel.register('fireIntentForContext', this.handleFiredIntentForContext.bind(this));
+ // Platform window functions
+ channel.register('getContextGroups', this.getContextGroups.bind(this));
+ channel.register('joinContextGroup', this.joinContextGroup.bind(this));
+ channel.register('removeFromContextGroup', this.removeFromContextGroup.bind(this));
+ channel.register('getAllClientsInContextGroup', this.getAllClientsInContextGroup.bind(this));
+ channel.register('getInfoForContextGroup', this.getInfoForContextGroup.bind(this));
+ // Internal methods
+ channel.register('contextHandlerRegistered', this.contextHandlerRegistered.bind(this));
+ channel.register('intentHandlerRegistered', this.intentHandlerRegistered.bind(this));
+ channel.register('removeContextHandler', this.removeContextHandler.bind(this));
+ channel.register('sessionContextGroup:createIfNeeded', this.handleJoinSessionContextGroup.bind(this));
+ // fdc3 only methods
+ channel.register('fdc3Open', this.fdc3HandleOpen.bind(this));
+ channel.register('fdc3v2FindIntentsByContext', this.handleInfoForIntentsByContext.bind(this));
+ channel.register('fdc3FindInstances', this.fdc3HandleFindInstances.bind(this));
+ channel.register('fdc3GetAppMetadata', this.fdc3HandleGetAppMetadata.bind(this));
+ channel.register('fdc3v2GetInfo', async (payload, clientIdentity) => {
+ return this.fdc3HandleGetInfo.bind(this)(payload, clientIdentity);
+ });
+ channel.register('createPrivateChannelProvider', async (payload) => {
+ const { channelId } = payload;
+ const channelProvider = await this.fin.InterApplicationBus.Channel.create(channelId);
+ PrivateChannelProvider_1.PrivateChannelProvider.init(channelProvider, channelId);
+ });
+ }
+ /**
+ * Can be used to completely prevent a connection. Return false to prevent connections. Allows all connections by default.
+ * @param _id the identity tryinc to connect
+ * @param _connectionPayload optional payload to use in custom implementations, will be undefined by default
+ */
+ isConnectionAuthorized(_id, _connectionPayload) {
+ this.wire.sendAction('interop-broker-is-connection-authorized').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ return Promise.resolve(true);
+ }
+ /**
+ * Called before every action to check if this entity should be allowed to take the action.
+ * Return false to prevent the action
+ * @param _action the string action to authorize in camel case
+ * @param _payload the data being sent for this action
+ * @param _identity the connection attempting to dispatch this action
+ */
+ isActionAuthorized(_action, _payload, _identity) {
+ this.wire.sendAction('interop-broker-is-action-authorized').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ return Promise.resolve(true);
+ }
+ };
+ InteropBroker.InteropBroker = InteropBroker$1;
+ return InteropBroker;
+}
+
+var InteropClient$1 = {};
+
+var SessionContextGroupClient$1 = {};
+
+var __classPrivateFieldSet$3 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$3 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _SessionContextGroupClient_clientPromise;
+Object.defineProperty(SessionContextGroupClient$1, "__esModule", { value: true });
+const base_1$3 = base;
+const utils_1$3 = utils$1;
+class SessionContextGroupClient extends base_1$3.Base {
+ constructor(wire, client, id) {
+ super(wire);
+ _SessionContextGroupClient_clientPromise.set(this, void 0);
+ this.id = id;
+ __classPrivateFieldSet$3(this, _SessionContextGroupClient_clientPromise, client, "f");
+ }
+ /**
+ * Sets a context for the session context group.
+ * @param context - New context to set.
+ *
+ * @tutorial interop.setContext
+ */
+ async setContext(context) {
+ this.wire.sendAction('interop-session-context-group-set-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$3(this, _SessionContextGroupClient_clientPromise, "f");
+ return client.dispatch(`sessionContextGroup:setContext-${this.id}`, {
+ sessionContextGroupId: this.id,
+ context
+ });
+ }
+ async getCurrentContext(type) {
+ this.wire.sendAction('interop-session-context-group-get-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$3(this, _SessionContextGroupClient_clientPromise, "f");
+ return client.dispatch(`sessionContextGroup:getContext-${this.id}`, {
+ sessionContextGroupId: this.id,
+ type
+ });
+ }
+ async addContextHandler(contextHandler, contextType) {
+ this.wire.sendAction('interop-session-context-group-add-handler').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ if (typeof contextHandler !== 'function') {
+ throw new Error("Non-function argument passed to the first parameter 'handler'. Be aware that the argument order does not match the FDC3 standard.");
+ }
+ const client = await __classPrivateFieldGet$3(this, _SessionContextGroupClient_clientPromise, "f");
+ let handlerId;
+ if (contextType) {
+ handlerId = `sessionContextHandler:invoke-${this.id}-${contextType}-${(0, utils_1$3.generateId)()}`;
+ }
+ else {
+ handlerId = `sessionContextHandler:invoke-${this.id}`;
+ }
+ client.register(handlerId, (0, utils_1$3.wrapContextHandler)(contextHandler, handlerId));
+ await client.dispatch(`sessionContextGroup:handlerAdded-${this.id}`, { handlerId, contextType });
+ return { unsubscribe: await this.createUnsubscribeCb(handlerId) };
+ }
+ async createUnsubscribeCb(handlerId) {
+ const client = await __classPrivateFieldGet$3(this, _SessionContextGroupClient_clientPromise, "f");
+ return async () => {
+ client.remove(handlerId);
+ await client.dispatch(`sessionContextGroup:handlerRemoved-${this.id}`, { handlerId });
+ };
+ }
+ getUserInstance() {
+ return {
+ id: this.id,
+ setContext: (0, utils_1$3.wrapInTryCatch)(this.setContext.bind(this), 'Failed to set context: '),
+ getCurrentContext: (0, utils_1$3.wrapInTryCatch)(this.getCurrentContext.bind(this), 'Failed to get context: '),
+ addContextHandler: (0, utils_1$3.wrapInTryCatch)(this.addContextHandler.bind(this), 'Failed to add context handler: ')
+ };
+ }
+}
+SessionContextGroupClient$1.default = SessionContextGroupClient;
+_SessionContextGroupClient_clientPromise = new WeakMap();
+
+var __classPrivateFieldSet$2 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$2 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _InteropClient_clientPromise, _InteropClient_sessionContextGroups;
+Object.defineProperty(InteropClient$1, "__esModule", { value: true });
+InteropClient$1.InteropClient = void 0;
+const base_1$2 = base;
+const SessionContextGroupClient_1 = SessionContextGroupClient$1;
+const utils_1$2 = utils$1;
+/**
+ * @PORTED
+ * @typedef { object } Intent
+ * @summary The combination of an action and a context that is passed to an application for resolution.
+ * @property { string } name Name of the intent.
+ * @property { Context } context Data associated with the intent
+ */
+/**
+ * @REMOVED
+ * @typedef { object } Subscription
+ * @summary Object returned when subscribing a handler.
+ * @property { function } unsubscribe Function to unsubscribe the handler.
+ */
+/**
+ * @typedef { function } ContextHandler
+ * @summary Subscription function for addContextHandler.
+ */
+/**
+ * @typedef { function } IntentHandler
+ * @summary Subscription function for registerIntentHandler
+ */
+/**
+ * @PORTED
+ * @typedef { object } ClientIdentity
+ * @summary The Identity for a Channel Client. Includes endpointId to differentiate between different connections for an entity.
+ * @property {string} uuid GUID of an application.
+ * @property {string} name Name of an entity in an application.
+ * @property {string} endpointId Unique differentiator for different Channel connections for an entity.
+ */
+/**
+ * @PORTED
+ * @typedef { object } ContextGroupInfo
+ * @summary Information for a Context Group. Contains metadata for displaying the group properly.
+ * @property {string} id Name of the context group
+ * @property {DisplayMetadata} displayMetadata Metadata for the Context Group. Contains the group's human-readable name, color, and an image, as defined by the Interop Broker.
+ */
+/**
+ * @PORTED
+ * @typedef { object } DisplayMetadata
+ * @summary The display data for a Context Group.
+ * @property {string} name A user-readable name for this context group, e.g: `"Red"`
+ * @property {string} [color] The color that should be associated within this context group when displaying this context group in a UI, e.g: `0xFF0000`.
+ * @property {string} [glyph] A URL of an image that can be used to display this context group
+ */
+/**
+ * @PORTED
+ * @typedef { object } Context
+ * @summary Data passed between entities and applications.
+ * @property {object} [id] An object containing string key-value pairs for the bulk of the data for the context. Differs between context types.
+ * @property {string} [name] User-readable name for the incoming context.
+ * @property {string} type Conserved type for the context (e.g. `instrument` or `country`)
+ */
+/**
+ * @REMOVED
+ * @typedef { object } ContextForIntent
+ * @summary Data passed between entities and applications, including an optional metadata.
+ * @property {object} [id] An object containing string key-value pairs for the bulk of the data for the context. Differs between context types.
+ * @property {string} [name] User-readable name for the incoming context.
+ * @property {string} type Conserved type for the context (e.g. `instrument` or `country`)
+ * @property {any} [metadata]
+ */
+/**
+ * @REMOVED
+ * @typedef { object } SessionContextGroup
+ * @summary An instance of a SessionContextGroup
+ * @property {string} id The SessionContextGroup's id.
+ * @property {setContext} setContext Sets a context of a certain type
+ * @property {getCurrentContext} getCurrentContext Gets the currently set context of a certain type
+ * @property {addContextHandler} addContextHandler Adds a handler for context change.
+ */
+/**
+ * @typedef {function} setContext
+ * @summary A SessionContextGroup instance method for setting a context in the SessionContextGroup.
+ * @param context The Context to be set.
+ *
+ */
+/**
+ * @typedef {function} getCurrentContext
+ * @summary A SessionContextGroup instance method for getting the current context of a certain type.
+ * @param contextType The Context Type to get. If not specified the last contextType set would get used.
+ *
+ */
+/**
+ * @typedef {function} addContextHandler
+ * @summary A SessionContextGroup instance method for adding a handler for context change.
+ * @param contextHandler The callback to be invoked. Is invoked when (a) the context changes or (b) immediately after getting created if the context is already set.
+ * @param contextType The context type this handler should listen to. If not specified, a global handler for all context types will get created. Only one global handler is allowed per SessionContextGroup.
+ *
+ */
+/**
+ * The Interop Client API is broken up into two groups:
+ *
+ * **Content Facing APIs** - For Application Developers putting Views into a Platform Window, who care about Context. These are APIs that send out and receive the Context data that flows between applications. Think of this as the Water in the Interop Pipes.
+ *
+ * **Context Grouping APIs** - For Platform Developers, to add and remove Views to and from Context Groups. These APIs are utilized under-the-hood in Platforms, so they don't need to be used to participate in Interop. These are the APIs that decide which entities the context data flows between. Think of these as the valves or pipes that control the flow of Context Data for Interop.
+ *
+ * ---
+ *
+ * All APIs are available at the `fin.me.interop` namespace.
+ *
+ * ---
+ *
+ * **You only need 2 things to participate in Interop Context Grouping:**
+ * * A Context Handler for incoming context: {@link InteropClient#addContextHandler addContextHandler(handler, contextType?)}
+ * * Call setContext on your context group when you want to share context with other group members: {@link InteropClient#setContext setContext(context)}
+ *
+ * ---
+ *
+ * ##### Constructor
+ * Returned by {@link Interop.connectSync Interop.connectSync}.
+ *
+ * ---
+ *
+ * ##### Interop methods intended for Views
+ *
+ *
+ * **Context Groups API**
+ * * {@link InteropClient#addContextHandler addContextHandler(handler, contextType?)}
+ * * {@link InteropClient#setContext setContext(context)}
+ * * {@link InteropClient#getCurrentContext getCurrentContext(contextType?)}
+ * * {@link InteropClient#joinSessionContextGroup joinSessionContextGroup(sessionContextGroupId)}
+ *
+ *
+ * **Intents API**
+ * * {@link InteropClient#fireIntent fireIntent(intent)}
+ * * {@link InteropClient#registerIntentHandler registerIntentHandler(intentHandler, intentName)}
+ * * {@link InteropClient#getInfoForIntent getInfoForIntent(infoForIntentOptions)}
+ * * {@link InteropClient#getInfoForIntentsByContext getInfoForIntentsByContext(context)}
+ * * {@link InteropClient#fireIntentForContext fireIntentForContext(contextForIntent)}
+ *
+ * ##### Interop methods intended for Windows
+ * * {@link InteropClient#getContextGroups getContextGroups()}
+ * * {@link InteropClient#joinContextGroup joinContextGroup(contextGroupId, target?)}
+ * * {@link InteropClient#removeFromContextGroup removeFromContextGroup(target?)}
+ * * {@link InteropClient#getInfoForContextGroup getInfoForContextGroup(contextGroupId)}
+ * * {@link InteropClient#getAllClientsInContextGroup getAllClientsInContextGroup(contextGroupId)}
+ *
+ */
+class InteropClient extends base_1$2.Base {
+ /**
+ * @internal
+ */
+ constructor(wire, name, interopConfig = {}) {
+ super(wire);
+ _InteropClient_clientPromise.set(this, void 0);
+ _InteropClient_sessionContextGroups.set(this, void 0);
+ __classPrivateFieldSet$2(this, _InteropClient_sessionContextGroups, new Map(), "f");
+ __classPrivateFieldSet$2(this, _InteropClient_clientPromise, this.wire.environment.whenReady().then(() => {
+ return this.fin.InterApplicationBus.Channel.connect(`interop-broker-${name}`, {
+ payload: interopConfig
+ });
+ }), "f");
+ }
+ /*
+ Client APIs
+ */
+ /**
+ * Sets a context for the context group of the current entity.
+ *
+ * @remarks The entity must be part of a context group in order set a context.
+ *
+ * @param context - New context to set.
+ *
+ * @example
+ * ```js
+ * setInstrumentContext = async (ticker) => {
+ * fin.me.interop.setContext({type: 'instrument', id: {ticker}})
+ * }
+ *
+ * // The user clicks an instrument of interest. We want to set that Instrument context so that the rest of our workflow updates with information for that instrument
+ * instrumentElement.on('click', (evt) => {
+ * setInstrumentContext(evt.ticker)
+ * })
+ * ```
+ */
+ async setContext(context) {
+ this.wire.sendAction('interop-client-set-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('setContext', { context });
+ }
+ /**
+ * Add a context handler for incoming context. If an entity is part of a context group, and then sets its context handler,
+ * it will receive all of its declared contexts.
+ *
+ * @param handler - Handler for incoming context.
+ * @param contextType - The type of context you wish to handle.
+ *
+ * @example
+ * ```js
+ * function handleIncomingContext(contextInfo) {
+ * const { type, id } = contextInfo;
+ * switch (type) {
+ * case 'instrument':
+ * handleInstrumentContext(contextInfo);
+ * break;
+ * case 'country':
+ * handleCountryContext(contextInfo);
+ * break;
+ *
+ * default:
+ * break;
+ * }
+ * }
+ *
+ *
+ * function handleInstrumentContext(contextInfo) {
+ * const { type, id } = contextInfo;
+ * console.log('contextInfo for instrument', contextInfo)
+ * }
+ *
+ * function handleCountryContext(contextInfo) {
+ * const { type, id } = contextInfo;
+ * console.log('contextInfo for country', contextInfo)
+ * }
+ *
+ * fin.me.interop.addContextHandler(handleIncomingContext);
+ * ```
+ *
+ *
+ * We are also testing the ability to add a context handler for specific contexts. If you would like to use
+ * this, please make sure you add your context handlers at the top level of your application, on a page that
+ * does not navigate/reload/re-render, to avoid memory leaks. This feature is experimental:
+ *
+ * ```js
+ * function handleInstrumentContext(contextInfo) {
+ * const { type, id } = contextInfo;
+ * console.log('contextInfo for instrument', contextInfo)
+ * }
+ *
+ * function handleCountryContext(contextInfo) {
+ * const { type, id } = contextInfo;
+ * console.log('contextInfo for country', contextInfo)
+ * }
+ *
+ *
+ * fin.me.interop.addContextHandler(handleInstrumentContext, 'instrument')
+ * fin.me.interop.addContextHandler(handleCountryContext, 'country')
+ * ```
+ */
+ async addContextHandler(handler, contextType) {
+ this.wire.sendAction('interop-client-add-context-handler').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ if (typeof handler !== 'function') {
+ throw new Error("Non-function argument passed to the first parameter 'handler'. Be aware that the argument order does not match the FDC3 standard.");
+ }
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ let handlerId;
+ if (contextType) {
+ handlerId = `invokeContextHandler-${contextType}-${(0, utils_1$2.generateId)()}`;
+ console.warn(`Warning: By providing a contextType (${contextType}), you are using the experimental addContextHandler. To avoid issues, make sure you are adding your context handlers at the top level in your application.`);
+ }
+ else {
+ handlerId = 'invokeContextHandler';
+ }
+ const wrappedHandler = (0, utils_1$2.wrapContextHandler)(handler, handlerId);
+ client.register(handlerId, wrappedHandler);
+ await client.dispatch('contextHandlerRegistered', { handlerId, contextType });
+ return {
+ unsubscribe: async () => {
+ client.remove(handlerId);
+ await client.dispatch('removeContextHandler', { handlerId });
+ }
+ };
+ }
+ /*
+ Platform Window APIs
+ */
+ /**
+ * Returns the Interop-Broker-defined context groups available for an entity to join.
+ * Used by Platform Windows.
+ *
+ * @example
+ * ```js
+ * fin.me.interop.getContextGroups()
+ * .then(contextGroups => {
+ * contextGroups.forEach(contextGroup => {
+ * console.log(contextGroup.displayMetadata.name)
+ * console.log(contextGroup.displayMetadata.color)
+ * })
+ * })
+ * ```
+ */
+ async getContextGroups() {
+ this.wire.sendAction('interop-client-get-context-groups').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('getContextGroups');
+ }
+ /**
+ * Join all Interop Clients at the given identity to context group `contextGroupId`.
+ * If no target is specified, it adds the sender to the context group.
+ *
+ * @remarks Because multiple Channel connections/Interop Clients can potentially exist at a `uuid`/`name` combo, we currently join all Channel connections/Interop Clients at the given identity to the context group.
+ * If an `endpointId` is provided (which is unlikely, unless the call is coming from an external adapter), then we only join that single connection to the context group.
+ * For all intents and purposes, there will only be 1 connection present in Platform and Browser implmentations, so this point is more-or-less moot.
+ * Used by Platform Windows.
+ *
+ * @param contextGroupId - Id of the context group.
+ * @param target - Identity of the entity you wish to join to a context group.
+ *
+ * @example
+ * ```js
+ * joinViewToContextGroup = async (contextGroupId, view) => {
+ * await fin.me.interop.joinContextGroup(contextGroupId, view);
+ * }
+ *
+ * getLastFocusedView()
+ * .then(lastFocusedViewIdentity => {
+ * joinViewToContextGroup('red', lastFocusedViewIdentity)
+ * })
+ * ```
+ */
+ async joinContextGroup(contextGroupId, target) {
+ this.wire.sendAction('interop-client-join-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ if (!contextGroupId) {
+ throw new Error('No contextGroupId specified for joinContextGroup.');
+ }
+ return client.dispatch('joinContextGroup', { contextGroupId, target });
+ }
+ /**
+ * Removes the specified target from a context group.
+ * If no target is specified, it removes the sender from their context group.
+ * Used by Platform Windows.
+ *
+ * @param target - Identity of the entity you wish to join to a context group.
+ *
+ * @example
+ * ```js
+ * removeViewFromContextGroup = async (view) => {
+ * await fin.me.interop.removeFromContextGroup(view);
+ * }
+ *
+ * getLastFocusedView()
+ * .then(lastFocusedViewIdentity => {
+ * removeViewFromContextGroup(lastFocusedViewIdentity)
+ * })
+ * ```
+ */
+ async removeFromContextGroup(target) {
+ this.wire.sendAction('interop-client-remove-from-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('removeFromContextGroup', { target });
+ }
+ /**
+ * Gets all clients for a context group.
+ *
+ * @remarks **This is primarily used for platform windows. Views within a platform should not have to use this API.**
+ *
+ * Returns the Interop-Broker-defined context groups available for an entity to join.
+ * @param contextGroupId - The id of context group you wish to get clients for.
+ *
+ * @example
+ * ```js
+ * fin.me.interop.getAllClientsInContextGroup('red')
+ * .then(clientsInContextGroup => {
+ * console.log(clientsInContextGroup)
+ * })
+ * ```
+ */
+ async getAllClientsInContextGroup(contextGroupId) {
+ this.wire.sendAction('interop-client-get-all-clients-in-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ if (!contextGroupId) {
+ throw new Error('No contextGroupId specified for getAllClientsInContextGroup.');
+ }
+ return client.dispatch('getAllClientsInContextGroup', { contextGroupId });
+ }
+ /**
+ * Gets display info for a context group
+ *
+ * @remarks Used by Platform Windows.
+ * @param contextGroupId - The id of context group you wish to get display info for.
+ *
+ * @example
+ * ```js
+ * fin.me.interop.getInfoForContextGroup('red')
+ * .then(contextGroupInfo => {
+ * console.log(contextGroupInfo.displayMetadata.name)
+ * console.log(contextGroupInfo.displayMetadata.color)
+ * })
+ * ```
+ */
+ async getInfoForContextGroup(contextGroupId) {
+ this.wire.sendAction('interop-client-get-info-for-context-group').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ if (!contextGroupId) {
+ throw new Error('No contextGroupId specified for getInfoForContextGroup.');
+ }
+ return client.dispatch('getInfoForContextGroup', { contextGroupId });
+ }
+ /**
+ * Sends an intent to the Interop Broker to resolve.
+ * @param intent - The combination of an action and a context that is passed to an application for resolution.
+ *
+ * @example
+ * ```js
+ * // View wants to fire an Intent after a user clicks on a ticker
+ * tickerElement.on('click', (element) => {
+ * const ticker = element.innerText;
+ * const intent = {
+ * name: 'ViewChart',
+ * context: {type: 'fdc3.instrument', id: { ticker }}
+ * }
+ *
+ * fin.me.interop.fireIntent(intent);
+ * })
+ * ```
+ */
+ async fireIntent(intent) {
+ this.wire.sendAction('interop-client-fire-intent').catch((e) => {
+ // don't expose, this is only for api analytics purposes
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('fireIntent', intent);
+ }
+ /**
+ * Adds an intent handler for incoming intents. The last intent sent of the name subscribed to will be received.
+ * @param handler - Registered function meant to handle a specific intent type.
+ * @param intentName - The name of an intent.
+ *
+ * @example
+ * ```js
+ * const intentHandler = (intent) => {
+ * const { context } = intent;
+ * myViewChartHandler(context);
+ * };
+ *
+ * const subscription = await fin.me.interop.registerIntentHandler(intentHandler, 'ViewChart');
+ *
+ * function myAppCloseSequence() {
+ * // to unsubscribe the handler, simply call:
+ * subscription.unsubscribe();
+ * }
+ * ```
+ */
+ async registerIntentHandler(handler, intentName, options) {
+ this.wire.sendAction('interop-client-register-intent-handler').catch((e) => {
+ // don't expose, this is only for api analytics purposes
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ const handlerId = `intent-handler-${intentName}`;
+ const wrappedHandler = (0, utils_1$2.wrapIntentHandler)(handler, handlerId);
+ try {
+ await client.register(handlerId, wrappedHandler);
+ await client.dispatch('intentHandlerRegistered', { handlerId, ...options });
+ }
+ catch (error) {
+ throw new Error('Unable to register intent handler');
+ }
+ return {
+ unsubscribe: async () => {
+ client.remove(handlerId);
+ }
+ };
+ }
+ /**
+ * Gets the last context of the Context Group currently subscribed to. It takes an optional Context Type and returns the
+ * last context of that type.
+ * @param contextType
+ *
+ * @example
+ * ```js
+ * await fin.me.interop.joinContextGroup('yellow');
+ * await fin.me.interop.setContext({ type: 'instrument', id: { ticker: 'FOO' }});
+ * const currentContext = await fin.me.interop.getCurrentContext();
+ *
+ * // with a specific context
+ * await fin.me.interop.joinContextGroup('yellow');
+ * await fin.me.interop.setContext({ type: 'country', id: { ISOALPHA3: 'US' }});
+ * await fin.me.interop.setContext({ type: 'instrument', id: { ticker: 'FOO' }});
+ * const currentContext = await fin.me.interop.getCurrentContext('country');
+ * ```
+ */
+ async getCurrentContext(contextType) {
+ this.wire.sendAction('interop-client-get-current-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('getCurrentContext', { contextType });
+ }
+ /**
+ * Get information for a particular Intent from the Interop Broker.
+ *
+ * @remarks To resolve this info, the function handleInfoForIntent is meant to be overridden in the Interop Broker.
+ * The format for the response will be determined by the App Provider overriding the function.
+ *
+ * @param options
+ *
+ * @example
+ * ```js
+ * const intentInfo = await fin.me.interop.getInfoForIntent('ViewChart');
+ * ```
+ */
+ async getInfoForIntent(options) {
+ this.wire.sendAction('interop-client-get-info-for-intent').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('getInfoForIntent', options);
+ }
+ /**
+ * Get information from the Interop Broker on all Intents that are meant to handle a particular context.
+ *
+ * @remarks To resolve this info, the function handleInfoForIntentsByContext is meant to be overridden in the Interop Broker.
+ * The format for the response will be determined by the App Provider overriding the function.
+ *
+ * @param context
+ *
+ * @example
+ * ```js
+ * tickerElement.on('click', (element) => {
+ * const ticker = element.innerText;
+ *
+ * const context = {
+ * type: 'fdc3.instrument',
+ * id: {
+ * ticker
+ * }
+ * }
+ *
+ * const intentsInfo = await fin.me.interop.getInfoForIntentByContext(context);
+ * })
+ * ```
+ */
+ async getInfoForIntentsByContext(context) {
+ this.wire.sendAction('interop-client-get-info-for-intents-by-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('getInfoForIntentsByContext', context);
+ }
+ /**
+ * Sends a Context that will be resolved to an Intent by the Interop Broker.
+ * This context accepts a metadata property.
+ *
+ * @remarks To resolve this info, the function handleFiredIntentByContext is meant to be overridden in the Interop Broker.
+ * The format for the response will be determined by the App Provider overriding the function.
+ *
+ * @param context
+ *
+ * @example
+ * ```js
+ * tickerElement.on('click', (element) => {
+ * const ticker = element.innerText;
+ *
+ * const context = {
+ * type: 'fdc3.instrument',
+ * id: {
+ * ticker
+ * }
+ * }
+ *
+ * const intentResolution = await fin.me.interop.fireIntentForContext(context);
+ * })
+ * ```
+ */
+ async fireIntentForContext(context) {
+ this.wire.sendAction('interop-client-fire-intent-for-context').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.dispatch('fireIntentForContext', context);
+ }
+ /**
+ * Join the current entity to session context group `sessionContextGroupId` and return a sessionContextGroup instance.
+ * If the sessionContextGroup doesn't exist, one will get created.
+ *
+ * @remarks Session Context Groups do not persist between runs and aren't present on snapshots.
+ * @param sessionContextGroupId - Id of the context group.
+ *
+ * @example
+ * Say we want to have a Session Context Group that holds UI theme information for all apps to consume:
+ *
+ * My color-picker View:
+ * ```js
+ * const themeSessionContextGroup = await fin.me.interop.joinSessionContextGroup('theme');
+ *
+ * const myColorPickerElement = document.getElementById('color-palette-picker');
+ * myColorPickerElement.addEventListener('change', event => {
+ * themeSessionContextGroup.setContext({ type: 'color-palette', selection: event.value });
+ * });
+ * ```
+ *
+ * In other views:
+ * ```js
+ * const themeSessionContextGroup = await fin.me.interop.joinSessionContextGroup('theme');
+ *
+ * const changeColorPalette = ({ selection }) => {
+ * // change the color palette to the selection
+ * };
+ *
+ * // If the context is already set by the time the handler was set, the handler will get invoked immediately with the current context.
+ * themeSessionContextGroup.addContextHandler(changeColorPalette, 'color-palette');
+ * ```
+ */
+ async joinSessionContextGroup(sessionContextGroupId) {
+ try {
+ const currentSessionContextGroup = __classPrivateFieldGet$2(this, _InteropClient_sessionContextGroups, "f").get(sessionContextGroupId);
+ if (currentSessionContextGroup) {
+ return currentSessionContextGroup.getUserInstance();
+ }
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ const { hasConflict } = await client.dispatch('sessionContextGroup:createIfNeeded', {
+ sessionContextGroupId
+ });
+ if (hasConflict) {
+ console.warn(`A (non-session) context group with the name "${sessionContextGroupId}" already exists. If you are trying to join a Context Group, call joinContextGroup instead.`);
+ }
+ const newSessionContextGroup = new SessionContextGroupClient_1.default(this.wire, __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f"), sessionContextGroupId);
+ __classPrivateFieldGet$2(this, _InteropClient_sessionContextGroups, "f").set(sessionContextGroupId, newSessionContextGroup);
+ return newSessionContextGroup.getUserInstance();
+ }
+ catch (error) {
+ console.error(`Error thrown trying to create Session Context Group with id "${sessionContextGroupId}": ${error}`);
+ throw error;
+ }
+ }
+ /**
+ * Register a listener that is called when the Interop Client has been disconnected from the Interop Broker.
+ * Only one listener per Interop Client can be set.
+ * @param listener
+ *
+ * @example
+ * ```js
+ * const listener = (event) => {
+ * const { type, topic, brokerName} = event;
+ * console.log(`Disconnected from Interop Broker ${brokerName} `);
+ * }
+ *
+ * await fin.me.interop.onDisconnection(listener);
+ * ```
+ */
+ async onDisconnection(listener) {
+ this.wire.sendAction('interop-client-add-ondisconnection-listener').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$2(this, _InteropClient_clientPromise, "f");
+ return client.onDisconnection((event) => {
+ const { uuid } = event;
+ listener({ type: 'interop-broker', topic: 'disconnected', brokerName: uuid });
+ });
+ }
+ /**
+ * @internal
+ *
+ * Used to ferry fdc3-only calls from the fdc3 shim to the Interop Broker
+ */
+ static async ferryFdc3Call(interopClient, action, payload) {
+ const client = await __classPrivateFieldGet$2(interopClient, _InteropClient_clientPromise, "f");
+ return client.dispatch(action, payload || null);
+ }
+}
+InteropClient$1.InteropClient = InteropClient;
+_InteropClient_clientPromise = new WeakMap(), _InteropClient_sessionContextGroups = new WeakMap();
+
+var overrideCheck = {};
+
+var hasRequiredOverrideCheck;
+
+function requireOverrideCheck () {
+ if (hasRequiredOverrideCheck) return overrideCheck;
+ hasRequiredOverrideCheck = 1;
+ Object.defineProperty(overrideCheck, "__esModule", { value: true });
+ overrideCheck.overrideCheck = overrideCheck.checkFDC32Overrides = overrideCheck.getDefaultViewFdc3VersionFromAppInfo = void 0;
+ const InteropBroker_1 = requireInteropBroker();
+ function getDefaultViewFdc3VersionFromAppInfo({ manifest, initialOptions }) {
+ const setVersion = manifest.platform?.defaultViewOptions?.fdc3InteropApi ?? initialOptions.defaultViewOptions?.fdc3InteropApi;
+ return ['1.2', '2.0'].includes(setVersion ?? '') ? setVersion : undefined;
+ }
+ overrideCheck.getDefaultViewFdc3VersionFromAppInfo = getDefaultViewFdc3VersionFromAppInfo;
+ function checkFDC32Overrides(overriddenBroker) {
+ // These are the APIs that must be overridden for FDC3 2.0 compliance
+ const mustOverrideAPIs = [
+ 'fdc3HandleFindInstances',
+ 'handleInfoForIntent',
+ 'handleInfoForIntentsByContext',
+ 'fdc3HandleGetAppMetadata',
+ 'fdc3HandleGetInfo',
+ 'fdc3HandleOpen',
+ 'handleFiredIntent',
+ 'handleFiredIntentForContext'
+ ];
+ return mustOverrideAPIs.filter((api) => {
+ return overriddenBroker[api] === InteropBroker_1.InteropBroker.prototype[api];
+ });
+ }
+ overrideCheck.checkFDC32Overrides = checkFDC32Overrides;
+ function overrideCheck$1(overriddenBroker, fdc3InteropApi) {
+ if (fdc3InteropApi && fdc3InteropApi === '2.0') {
+ const notOverridden = checkFDC32Overrides(overriddenBroker);
+ if (notOverridden.length > 0) {
+ console.warn(`WARNING: FDC3 2.0 has been set as a default option for Views in this Platform, but the required InteropBroker APIs for FDC3 2.0 compliance have not all been overridden.\nThe following APIs need to be overridden:\n${notOverridden.join('\n')}`);
+ }
+ }
+ }
+ overrideCheck.overrideCheck = overrideCheck$1;
+ return overrideCheck;
+}
+
+var hasRequiredFactory;
+
+function requireFactory () {
+ if (hasRequiredFactory) return Factory$1;
+ hasRequiredFactory = 1;
+ Object.defineProperty(Factory$1, "__esModule", { value: true });
+ Factory$1.InteropModule = void 0;
+ const lodash_1 = require$$3;
+ const inaccessibleObject_1 = inaccessibleObject;
+ const base_1 = base;
+ const InteropBroker_1 = requireInteropBroker();
+ const InteropClient_1 = InteropClient$1;
+ const overrideCheck_1 = requireOverrideCheck();
+ const common_utils_1 = commonUtils;
+ const defaultOverride = (Class) => new Class();
+ const BrokerParamAccessError = 'You have attempted to use or modify InteropBroker parameters, which is not allowed. You are likely using an older InteropBroker override scheme. Please consult our Interop docs for guidance on migrating to the new override scheme.';
+ /**
+ * @PORTED
+ * @typedef { object } InteropConfig
+ * @summary Information relevant to the Interop Broker.
+ * @property {string} [currentContextGroup] Context Group for the client. (green, yellow, red, etc.)
+ * @property {string} [providerId] When provided, automatically connects the client to the specified provider uuid
+ */
+ /**
+ * Manages creation of Interop Brokers and Interop Clients. These APIs are called under-the-hood in Platforms.
+ *
+ */
+ class InteropModule extends base_1.Base {
+ /**
+ * Initializes an Interop Broker. This is called under-the-hood for Platforms.
+ *
+ * @remarks For Platforms, this is set up automatically. We advise to only create your own Interop Broker
+ * when not using a Platform app. You can override functions in the Interop Broker. More info {@link InteropBroker here}.
+ *
+ * @param name - Name of the Interop Broker.
+ * @param override - A callback function or array of callback functions that can be used to extend or replace default Interop Broker behavior.
+ *
+ * @example
+ * ``` js
+ * const interopBroker = await fin.Interop.init('openfin');
+ * const contextGroups = await interopBroker.getContextGroups();
+ * console.log(contextGroups);
+ * ```
+ */
+ async init(name, override = defaultOverride) {
+ this.wire.sendAction('interop-init').catch(() => {
+ // don't expose, analytics-only call
+ });
+ // Allows for manifest-level configuration, without having to override. (e.g. specifying custom context groups)
+ const options = await this.fin.Application.getCurrentSync().getInfo();
+ const opts = options.initialOptions.interopBrokerConfiguration ?? {};
+ const objectThatThrows = (0, inaccessibleObject_1.createUnusableObject)(BrokerParamAccessError);
+ const warningOptsClone = (0, inaccessibleObject_1.createWarningObject)(BrokerParamAccessError, (0, lodash_1.cloneDeep)(opts));
+ let provider;
+ const getProvider = () => {
+ if (!provider) {
+ provider = this.fin.InterApplicationBus.Channel.create(`interop-broker-${name}`);
+ }
+ return provider;
+ };
+ const throwingGetProvider = async () => {
+ // eslint-disable-next-line no-console
+ throw new Error(BrokerParamAccessError);
+ };
+ const OverrideableBroker = InteropBroker_1.InteropBroker.createClosedConstructor(this.wire, getProvider, opts);
+ let broker;
+ if (Array.isArray(override)) {
+ const BrokerConstructor = (0, common_utils_1.overrideFromComposables)(...override)(OverrideableBroker);
+ // We need to use these objects because removing them entirely would be a breaking change and we want an informative error
+ // @ts-expect-error
+ broker = new BrokerConstructor(objectThatThrows, throwingGetProvider, warningOptsClone);
+ }
+ else {
+ // We need to use these objects because removing them entirely would be a breaking change and we want an informative error
+ // @ts-expect-error
+ broker = await override(OverrideableBroker, objectThatThrows, throwingGetProvider, warningOptsClone);
+ }
+ (0, overrideCheck_1.overrideCheck)(broker, (0, overrideCheck_1.getDefaultViewFdc3VersionFromAppInfo)(options));
+ return broker;
+ }
+ /**
+ * Connects a client to an Interop broker. This is called under-the-hood for Views in a Platform.
+ *
+ * @remarks
+ * @param name - The name of the Interop Broker to connect to. For Platforms, this will default to the uuid of the Platform.
+ * @param interopConfig - Information relevant to the Interop Broker. Typically a declaration of
+ * what context(s) the entity wants to subscribe to, and the current Context Group of the entity.
+ *
+ * @example
+ * ```js
+ * const interopConfig = {
+ * currentContextGroup: 'green'
+ * }
+ *
+ * const interopBroker = await fin.Interop.init('openfin');
+ * const client = await fin.Interop.connectSync('openfin', interopConfig);
+ * const contextGroupInfo = await client.getInfoForContextGroup();
+ * console.log(contextGroupInfo);
+ * ```
+ */
+ connectSync(name, interopConfig) {
+ this.wire.sendAction('interop-connect-sync').catch(() => {
+ // don't expose, analytics-only call
+ });
+ return new InteropClient_1.InteropClient(this.wire, name, interopConfig);
+ }
+ }
+ Factory$1.InteropModule = InteropModule;
+ return Factory$1;
+}
+
+var hasRequiredInterop;
+
+function requireInterop () {
+ if (hasRequiredInterop) return interop;
+ hasRequiredInterop = 1;
+ (function (exports) {
+ /**
+ * Entry point for the OpenFin `Interop` API (`fin.Interop`).
+ *
+ * * {@link InteropModule} contains static members of the `Interop` API (available under `fin.Interop`)
+ * * {@link InteropClient} and {@link InteropBroker} document instances of their respective classes.
+ *
+ * @packageDocumentation
+ */
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(requireFactory(), exports);
+ __exportStar(InteropClient$1, exports);
+ __exportStar(requireInteropBroker(), exports);
+ } (interop));
+ return interop;
+}
+
+var snapshotSource = {};
+
+var Factory = {};
+
+var Instance = {};
+
+var utils = {};
+
+Object.defineProperty(utils, "__esModule", { value: true });
+utils.getSnapshotSourceChannelName = void 0;
+const channelPrefix = 'snapshot-source-provider-';
+const getSnapshotSourceChannelName = (id) => `${channelPrefix}${id.uuid}`;
+utils.getSnapshotSourceChannelName = getSnapshotSourceChannelName;
+
+var __classPrivateFieldSet$1 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet$1 = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _SnapshotSource_identity, _SnapshotSource_getConnection, _SnapshotSource_getClient, _SnapshotSource_startConnection, _SnapshotSource_setUpConnectionListener;
+Object.defineProperty(Instance, "__esModule", { value: true });
+Instance.SnapshotSource = void 0;
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+const base_1$1 = base;
+const utils_1$1 = utils;
+const connectionMap = new Map();
+/**
+ * Enables configuring a SnapshotSource with custom getSnapshot and applySnapshot methods.
+ *
+ * @typeParam Snapshot Implementation-defined shape of an application snapshot. Allows
+ * custom snapshot implementations for legacy applications to define their own snapshot format.
+ */
+class SnapshotSource extends base_1$1.Base {
+ /**
+ * @internal
+ */
+ constructor(wire, id) {
+ super(wire);
+ _SnapshotSource_identity.set(this, void 0);
+ _SnapshotSource_getConnection.set(this, () => {
+ if (!connectionMap.has(this.identity.uuid)) {
+ connectionMap.set(this.identity.uuid, { eventFired: null, clientPromise: null });
+ }
+ return connectionMap.get(this.identity.uuid);
+ });
+ _SnapshotSource_getClient.set(this, () => {
+ if (!__classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).clientPromise) {
+ __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).clientPromise = __classPrivateFieldGet$1(this, _SnapshotSource_startConnection, "f").call(this);
+ }
+ return __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).clientPromise;
+ });
+ _SnapshotSource_startConnection.set(this, async () => {
+ const channelName = (0, utils_1$1.getSnapshotSourceChannelName)(this.identity);
+ try {
+ if (!__classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).eventFired) {
+ await __classPrivateFieldGet$1(this, _SnapshotSource_setUpConnectionListener, "f").call(this);
+ }
+ const client = await this.fin.InterApplicationBus.Channel.connect(channelName, { wait: false });
+ client.onDisconnection(() => {
+ __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).clientPromise = null;
+ __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).eventFired = null;
+ });
+ return client;
+ }
+ catch (e) {
+ __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).clientPromise = null;
+ throw new Error("The targeted SnapshotSource is not currently initialized. Await this object's ready() method.");
+ }
+ });
+ _SnapshotSource_setUpConnectionListener.set(this, async () => {
+ const channelName = (0, utils_1$1.getSnapshotSourceChannelName)(this.identity);
+ let resolve;
+ let reject;
+ const eventFired = new Promise((y, n) => {
+ resolve = y;
+ reject = n;
+ });
+ __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).eventFired = eventFired;
+ const listener = async (e) => {
+ try {
+ if (e.channelName === channelName) {
+ resolve();
+ await this.fin.InterApplicationBus.Channel.removeListener('connected', listener);
+ }
+ }
+ catch (err) {
+ reject(err);
+ }
+ };
+ await this.fin.InterApplicationBus.Channel.on('connected', listener);
+ });
+ __classPrivateFieldSet$1(this, _SnapshotSource_identity, id, "f");
+ }
+ get identity() {
+ return __classPrivateFieldGet$1(this, _SnapshotSource_identity, "f");
+ }
+ /**
+ * Method to determine if the SnapshotSource has been initialized.
+ *
+ * @remarks Use when the parent application is starting up to ensure the SnapshotSource is able to accept and
+ * apply a snapshot using the {@link SnapshotSource#applySnapshot applySnapshot} method.
+ *
+ * @example
+ * ```js
+ * let snapshotSource = fin.SnapshotSource.wrapSync(fin.me);
+ *
+ * const snapshotProvider = {
+ * async getSnapshot() { return 'foo' },
+ * async applySnapshot(snapshot) {
+ * console.log(snapshot);
+ * return undefined;
+ * }
+ * }
+ * await fin.SnapshotSource.init(snapshotProvider);
+ *
+ * try {
+ * await snapshotSource.ready();
+ * await snapshotSource.applySnapshot('foo');
+ * } catch (err) {
+ * console.log(err)
+ * }
+ * ```
+ */
+ async ready() {
+ this.wire.sendAction('snapshot-source-ready').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ // eslint-disable-next-line no-async-promise-executor
+ try {
+ // If getClient was already called before this, do we have a timing issue where the channel might have been created but we missed the event but this still fails?
+ await __classPrivateFieldGet$1(this, _SnapshotSource_getClient, "f").call(this);
+ }
+ catch (e) {
+ // it was not running.
+ await __classPrivateFieldGet$1(this, _SnapshotSource_getConnection, "f").call(this).eventFired;
+ }
+ }
+ /**
+ * Call the SnapshotSource's getSnapshot method defined by {@link SnapshotSource.SnapshotSourceModule#init init}.
+ *
+ */
+ async getSnapshot() {
+ this.wire.sendAction('snapshot-source-get-snapshot').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$1(this, _SnapshotSource_getClient, "f").call(this);
+ const response = (await client.dispatch('get-snapshot'));
+ return (await response).snapshot;
+ }
+ /**
+ * Call the SnapshotSource's applySnapshot method defined by {@link SnapshotSource.SnapshotSourceModule#init init}.
+ *
+ */
+ async applySnapshot(snapshot) {
+ this.wire.sendAction('snapshot-source-apply-snapshot').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ const client = await __classPrivateFieldGet$1(this, _SnapshotSource_getClient, "f").call(this);
+ return client.dispatch('apply-snapshot', { snapshot });
+ }
+}
+Instance.SnapshotSource = SnapshotSource;
+_SnapshotSource_identity = new WeakMap(), _SnapshotSource_getConnection = new WeakMap(), _SnapshotSource_getClient = new WeakMap(), _SnapshotSource_startConnection = new WeakMap(), _SnapshotSource_setUpConnectionListener = new WeakMap();
+
+Object.defineProperty(Factory, "__esModule", { value: true });
+Factory.SnapshotSourceModule = void 0;
+const base_1 = base;
+const Instance_1 = Instance;
+const utils_1 = utils;
+/**
+ * Static namespace for OpenFin API methods that interact with the {@link SnapshotSource} class, available under `fin.SnapshotSource`.
+ */
+class SnapshotSourceModule extends base_1.Base {
+ /**
+ * Initializes a SnapshotSource with the getSnapshot and applySnapshot methods defined.
+ *
+ * @typeParam Snapshot Implementation-defined shape of an application snapshot. Allows
+ * custom snapshot implementations for legacy applications to define their own snapshot format.
+ *
+ * @example
+ * ```js
+ * const snapshotProvider = {
+ * async getSnapshot() {
+ * const bounds = await fin.me.getBounds();
+ * return bounds;
+ * },
+ * async applySnapshot(snapshot) {
+ * await fin.me.setBounds(snapshot);
+ * return undefined;
+ * }
+ * }
+ *
+ * await fin.SnapshotSource.init(snapshotProvider);
+ * ```
+ *
+ */
+ async init(provider) {
+ this.wire.sendAction('snapshot-source-init').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ if (typeof provider !== 'object' ||
+ typeof provider.getSnapshot !== 'function' ||
+ typeof provider.applySnapshot !== 'function') {
+ throw new Error('you must pass in a valid SnapshotProvider');
+ }
+ const channel = await this.fin.InterApplicationBus.Channel.create((0, utils_1.getSnapshotSourceChannelName)(this.fin.me));
+ channel.register('get-snapshot', async () => {
+ const snapshot = await provider.getSnapshot();
+ return { snapshot };
+ });
+ channel.register('apply-snapshot', ({ snapshot }) => provider.applySnapshot(snapshot));
+ }
+ /**
+ * Synchronously returns a SnapshotSource object that represents the current SnapshotSource.
+ *
+ * @example
+ * ```js
+ * const snapshotSource = fin.SnapshotSource.wrapSync(fin.me);
+ * // Use wrapped instance's getSnapshot method, e.g.:
+ * const snapshot = await snapshotSource.getSnapshot();
+ * ```
+ */
+ wrapSync(identity) {
+ this.wire.sendAction('snapshot-source-wrap-sync').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ return new Instance_1.SnapshotSource(this.wire, identity);
+ }
+ /**
+ * Asynchronously returns a SnapshotSource object that represents the current SnapshotSource.
+ *
+ * @example
+ * ```js
+ * const snapshotSource = await fin.SnapshotSource.wrap(fin.me);
+ * // Use wrapped instance's getSnapshot method, e.g.:
+ * const snapshot = await snapshotSource.getSnapshot();
+ * ```
+ */
+ async wrap(identity) {
+ this.wire.sendAction('snapshot-source-wrap').catch((e) => {
+ // don't expose, analytics-only call
+ });
+ return this.wrapSync(identity);
+ }
+}
+Factory.SnapshotSourceModule = SnapshotSourceModule;
+
+(function (exports) {
+ /**
+ * Entry points for the OpenFin `SnapshotSource` API (`fin.SnapshotSource`).
+ *
+ * * {@link SnapshotSourceModule} contains static members of the `SnapshotSource` API, accessible through `fin.SnapshotSource`.
+ * * {@link SnapshotSource} describes an instance of an OpenFin SnapshotSource, e.g. as returned by `fin.SnapshotSource.wrap`.
+ *
+ * These are separate code entities, and are documented separately. In the [previous version of the API documentation](https://cdn.openfin.co/docs/javascript/32.114.76.10/index.html),
+ * both of these were documented on the same page.
+ *
+ * @packageDocumentation
+ */
+ var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+ }) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+ }));
+ var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+ };
+ Object.defineProperty(exports, "__esModule", { value: true });
+ __exportStar(Factory, exports);
+ __exportStar(Instance, exports);
+} (snapshotSource));
+
+Object.defineProperty(fin$1, "__esModule", { value: true });
+fin$1.Fin = void 0;
+const events_1$3 = require$$0;
+// Import from the file rather than the directory in case someone consuming types is using module resolution other than "node"
+const index_1 = system;
+const index_2 = requireWindow();
+const index_3 = requireApplication();
+const index_4 = interappbus;
+const index_5 = clipboard;
+const index_6 = externalApplication;
+const index_7 = frame;
+const index_8 = globalHotkey;
+const index_9 = requireView();
+const index_10 = platform;
+const me_1$2 = me;
+const interop_1 = requireInterop();
+const snapshot_source_1 = snapshotSource;
+/**
+ * @internal
+ */
+class Fin extends events_1$3.EventEmitter {
+ /**
+ * @internal
+ */
+ constructor(wire) {
+ super();
+ this.wire = wire;
+ this.System = new index_1.System(wire);
+ this.Window = new index_2._WindowModule(wire);
+ this.Application = new index_3.ApplicationModule(wire);
+ this.InterApplicationBus = new index_4.InterApplicationBus(wire);
+ this.Clipboard = new index_5.Clipboard(wire);
+ this.ExternalApplication = new index_6.ExternalApplicationModule(wire);
+ this.Frame = new index_7._FrameModule(wire);
+ this.GlobalHotkey = new index_8.GlobalHotkey(wire);
+ this.Platform = new index_10.PlatformModule(wire, this.InterApplicationBus.Channel);
+ this.View = new index_9.ViewModule(wire);
+ this.Interop = new interop_1.InteropModule(wire);
+ this.SnapshotSource = new snapshot_source_1.SnapshotSourceModule(wire);
+ wire.registerFin(this);
+ this.me = (0, me_1$2.getMe)(wire);
+ // Handle disconnect events
+ wire.on('disconnected', () => {
+ this.emit('disconnected');
+ });
+ }
+}
+fin$1.Fin = Fin;
+
+var transport = {};
+
+var wire = {};
+
+Object.defineProperty(wire, "__esModule", { value: true });
+wire.isInternalConnectConfig = wire.isPortDiscoveryConfig = wire.isNewConnectConfig = wire.isConfigWithReceiver = wire.isRemoteConfig = wire.isExistingConnectConfig = wire.isExternalConfig = void 0;
+function isExternalConfig(config) {
+ if (typeof config.manifestUrl === 'string') {
+ return true;
+ }
+ return false;
+}
+wire.isExternalConfig = isExternalConfig;
+function isExistingConnectConfig(config) {
+ return hasUuid(config) && typeof config.address === 'string';
+}
+wire.isExistingConnectConfig = isExistingConnectConfig;
+function isRemoteConfig(config) {
+ return isExistingConnectConfig(config) && typeof config.token === 'string';
+}
+wire.isRemoteConfig = isRemoteConfig;
+function isConfigWithReceiver(config) {
+ return typeof config.receiver === 'object' && isRemoteConfig({ ...config, address: '' });
+}
+wire.isConfigWithReceiver = isConfigWithReceiver;
+function hasUuid(config) {
+ return typeof config.uuid === 'string';
+}
+function hasRuntimeVersion(config) {
+ return config.runtime && typeof config.runtime.version === 'string';
+}
+function isNewConnectConfig(config) {
+ return hasUuid(config) && hasRuntimeVersion(config);
+}
+wire.isNewConnectConfig = isNewConnectConfig;
+function isPortDiscoveryConfig(config) {
+ return (isExternalConfig(config) && hasRuntimeVersion(config)) || isNewConnectConfig(config);
+}
+wire.isPortDiscoveryConfig = isPortDiscoveryConfig;
+function isInternalConnectConfig(config) {
+ return isExistingConnectConfig(config) || isNewConnectConfig(config);
+}
+wire.isInternalConnectConfig = isInternalConnectConfig;
+
+var eventAggregator = {};
+
+var emitterMap = {};
+
+Object.defineProperty(emitterMap, "__esModule", { value: true });
+emitterMap.EmitterMap = void 0;
+const events_1$2 = require$$0;
+class EmitterMap {
+ constructor() {
+ this.storage = new Map();
+ }
+ // eslint-disable-next-line class-methods-use-this
+ hashKeys(keys) {
+ const hashed = keys.map(normalizeString);
+ return hashed.join('/');
+ }
+ getOrCreate(keys) {
+ const hash = this.hashKeys(keys);
+ if (!this.storage.has(hash)) {
+ this.storage.set(hash, new events_1$2.EventEmitter());
+ }
+ // We set it above
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ return this.storage.get(hash);
+ }
+ has(keys) {
+ return this.storage.has(this.hashKeys(keys));
+ }
+ delete(keys) {
+ const hash = this.hashKeys(keys);
+ return this.storage.delete(hash);
+ }
+}
+emitterMap.EmitterMap = EmitterMap;
+function normalizeString(s) {
+ const b = Buffer.from(s);
+ return b.toString('base64');
+}
+
+Object.defineProperty(eventAggregator, "__esModule", { value: true });
+const emitterMap_1 = emitterMap;
+function isEventMessage(message) {
+ return message.action === 'process-desktop-event';
+}
+function mapKeyFromEvent(event) {
+ const { topic } = event;
+ if (topic === 'frame' || topic === 'window' || topic === 'view') {
+ const { uuid, name } = event;
+ return [topic, uuid, name];
+ }
+ if (topic === 'application') {
+ const { uuid } = event;
+ return [topic, uuid];
+ }
+ return [topic];
+}
+class EventAggregator extends emitterMap_1.EmitterMap {
+ constructor() {
+ super(...arguments);
+ this.dispatchEvent = (message) => {
+ if (isEventMessage(message)) {
+ const { payload } = message;
+ const accessor = mapKeyFromEvent(payload);
+ if (this.has(accessor)) {
+ this.getOrCreate(accessor).emit(payload.type, payload);
+ return true;
+ }
+ }
+ return false;
+ };
+ }
+}
+eventAggregator.default = EventAggregator;
+
+var __classPrivateFieldSet = (commonjsGlobal && commonjsGlobal.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet = (commonjsGlobal && commonjsGlobal.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _Transport_wire, _Transport_fin;
+Object.defineProperty(transport, "__esModule", { value: true });
+transport.Transport = void 0;
+const events_1$1 = require$$0;
+const wire_1 = wire;
+const transport_errors_1 = transportErrors;
+const eventAggregator_1 = eventAggregator;
+const me_1$1 = me;
+const errors_1 = errors;
+class Transport extends events_1$1.EventEmitter {
+ constructor(WireType, environment, config) {
+ super();
+ this.wireListeners = new Map();
+ this.topicRefMap = new Map();
+ this.eventAggregator = new eventAggregator_1.default();
+ this.messageHandlers = [this.eventAggregator.dispatchEvent];
+ _Transport_wire.set(this, void 0);
+ // Typing as unknown to avoid circular dependency, should not be used directly.
+ _Transport_fin.set(this, void 0);
+ this.connectSync = () => {
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ wire.connectSync();
+ };
+ // This function is only used in our tests.
+ this.getPort = () => {
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ return wire.getPort();
+ };
+ __classPrivateFieldSet(this, _Transport_wire, new WireType(this.onmessage.bind(this)), "f");
+ this.environment = environment;
+ this.sendRaw = __classPrivateFieldGet(this, _Transport_wire, "f").send.bind(__classPrivateFieldGet(this, _Transport_wire, "f"));
+ this.registerMessageHandler(this.handleMessage.bind(this));
+ __classPrivateFieldGet(this, _Transport_wire, "f").on('disconnected', () => {
+ for (const [, { handleNack }] of this.wireListeners) {
+ handleNack({ reason: 'Remote connection has closed' });
+ }
+ this.wireListeners.clear();
+ this.emit('disconnected');
+ });
+ const { uuid, name } = config;
+ const entityType = this.environment.getCurrentEntityType();
+ this.me = (0, me_1$1.getBaseMe)(entityType, uuid, name);
+ }
+ getFin() {
+ if (!__classPrivateFieldGet(this, _Transport_fin, "f")) {
+ throw new Error('No Fin object registered for this transport');
+ }
+ return __classPrivateFieldGet(this, _Transport_fin, "f");
+ }
+ registerFin(_fin) {
+ if (__classPrivateFieldGet(this, _Transport_fin, "f")) {
+ throw new Error('Fin object has already been registered for this transport');
+ }
+ __classPrivateFieldSet(this, _Transport_fin, _fin, "f");
+ }
+ shutdown() {
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ return wire.shutdown();
+ }
+ async connect(config) {
+ if ((0, wire_1.isConfigWithReceiver)(config)) {
+ await __classPrivateFieldGet(this, _Transport_wire, "f").connect(config.receiver);
+ return this.authorize(config);
+ }
+ if ((0, wire_1.isRemoteConfig)(config)) {
+ return this.connectRemote(config);
+ }
+ if ((0, wire_1.isExistingConnectConfig)(config)) {
+ return this.connectByPort(config);
+ }
+ if ((0, wire_1.isNewConnectConfig)(config)) {
+ const port = await this.environment.retrievePort(config);
+ return this.connectByPort({ ...config, address: `ws://localhost:${port}` });
+ }
+ return undefined;
+ }
+ async connectRemote(config) {
+ await __classPrivateFieldGet(this, _Transport_wire, "f").connect(new (this.environment.getWsConstructor())(config.address));
+ return this.authorize(config);
+ }
+ async connectByPort(config) {
+ const { address, uuid } = config;
+ const reqAuthPayload = { ...config, type: 'file-token' };
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ await wire.connect(new (this.environment.getWsConstructor())(config.address));
+ const requestExtAuthRet = await this.sendAction('request-external-authorization', {
+ uuid,
+ type: 'file-token'
+ }, true);
+ if (requestExtAuthRet.action !== 'external-authorization-response') {
+ throw new transport_errors_1.UnexpectedActionError(requestExtAuthRet.action);
+ }
+ await this.environment.writeToken(requestExtAuthRet.payload.file, requestExtAuthRet.payload.token);
+ return this.authorize(reqAuthPayload);
+ }
+ async authorize(reqAuthPayload) {
+ const requestAuthRet = await this.sendAction('request-authorization', reqAuthPayload, true);
+ if (requestAuthRet.action !== 'authorization-response') {
+ throw new transport_errors_1.UnexpectedActionError(requestAuthRet.action);
+ }
+ else if (requestAuthRet.payload.success !== true) {
+ throw new transport_errors_1.RuntimeError(requestAuthRet.payload);
+ }
+ }
+ sendAction(action, payload = {}, uncorrelated = false
+ // specialResponse type is only used for 'requestAuthorization'
+ ) {
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ let cancel = () => { };
+ // We want the callsite from the caller of this function, not from here.
+ const callSites = transport_errors_1.RuntimeError.getCallSite(1);
+ const messageId = this.environment.getNextMessageId();
+ const prom = new Promise((resolve, reject) => {
+ cancel = reject;
+ const msg = {
+ action,
+ payload,
+ messageId
+ };
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ this.addWireListener(messageId, resolve, (payload) => this.nackHandler(payload, reject, callSites), uncorrelated);
+ return wire.send(msg).catch(reject);
+ });
+ return Object.assign(prom, { cancel, messageId });
+ }
+ nackHandler(payloadOrMessage, reject, callSites) {
+ if (typeof payloadOrMessage === 'string') {
+ // NOTE: this is for backwards compatibility to support plain string rejections
+ reject(payloadOrMessage);
+ }
+ else {
+ reject(new transport_errors_1.RuntimeError(payloadOrMessage, callSites));
+ }
+ }
+ ferryAction(origData) {
+ return new Promise((resolve, reject) => {
+ const id = this.environment.getNextMessageId();
+ origData.messageId = id;
+ const resolver = (data) => {
+ resolve(data.payload);
+ };
+ const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
+ return wire
+ .send(origData)
+ .then(() => this.addWireListener(id, resolver, (payload) => this.nackHandler(payload, reject), false))
+ .catch(reject);
+ });
+ }
+ registerMessageHandler(handler) {
+ this.messageHandlers.push(handler);
+ }
+ addWireListener(id, resolve, handleNack, uncorrelated) {
+ if (uncorrelated) {
+ this.uncorrelatedListener = resolve;
+ }
+ else if (this.wireListeners.has(id)) {
+ handleNack({
+ reason: 'Duplicate handler id',
+ error: (0, errors_1.errorToPOJO)(new transport_errors_1.DuplicateCorrelationError(String(id)))
+ });
+ }
+ else {
+ this.wireListeners.set(id, { resolve, handleNack });
+ }
+ // Timeout and reject()?
+ }
+ // This method executes message handlers until the _one_ that handles the message (returns truthy) has run
+ onmessage(data) {
+ for (const h of this.messageHandlers) {
+ h.call(null, data);
+ }
+ }
+ handleMessage(data) {
+ const id = data.correlationId || NaN;
+ if (!('correlationId' in data)) {
+ if (this.uncorrelatedListener) {
+ this.uncorrelatedListener.call(null, data);
+ }
+ this.uncorrelatedListener = () => {
+ // empty block
+ };
+ }
+ else if (!this.wireListeners.has(id)) {
+ return false;
+ }
+ else {
+ // We just checked for existence above
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const { resolve, handleNack } = this.wireListeners.get(id);
+ if (data.action !== 'ack') {
+ handleNack({ reason: 'Did not receive ack action', error: (0, errors_1.errorToPOJO)(new transport_errors_1.NoAckError(data.action)) });
+ }
+ else if (!('payload' in data)) {
+ // I'm not sure when this code would actually run, but passing in something that doeesn't have a reason to the runtimeerror constructor will not end well.
+ // @ts-expect-error
+ if (typeof data.reason === 'string') {
+ handleNack(data);
+ }
+ else {
+ console.warn('Received invalid response from core', data);
+ handleNack({ reason: 'invalid response shape' });
+ }
+ }
+ else if (!data.payload.success) {
+ handleNack(data.payload);
+ }
+ else {
+ resolve.call(null, data);
+ }
+ this.wireListeners.delete(id);
+ }
+ return true;
+ }
+}
+transport.Transport = Transport;
+_Transport_wire = new WeakMap(), _Transport_fin = new WeakMap();
+
+var mockEnvironment = {};
+
+Object.defineProperty(mockEnvironment, "__esModule", { value: true });
+mockEnvironment.MockEnvironment = void 0;
+const me_1 = me;
+class MockEnvironment {
+ constructor() {
+ this.childViews = true;
+ }
+ getDefaultChannelOptions() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getRtcPeer() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ initLayoutManager() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ applyLayoutSnapshot() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ async createLayout() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ async destroyLayout() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ async resolveLayout() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ initPlatform() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ observeBounds() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ writeToken(path, token) {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ retrievePort(config) {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getNextMessageId() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getRandomId() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ createChildContent(options) {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getWebWindow(identity) {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getCurrentEntityIdentity() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getCurrentEntityType() {
+ return 'unknown';
+ }
+ raiseEvent(eventName, eventArgs) {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getUrl() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ whenReady() {
+ throw new Error(me_1.environmentUnsupportedMessage);
+ }
+ getWsConstructor() {
+ throw new Error('Method not implemented.');
+ }
+}
+mockEnvironment.MockEnvironment = MockEnvironment;
+
+var mockWire = {};
+
+Object.defineProperty(mockWire, "__esModule", { value: true });
+mockWire.MockWire = void 0;
+/* eslint-disable @typescript-eslint/no-unused-vars */
+const events_1 = require$$0;
+class MockWire extends events_1.EventEmitter {
+ connect() {
+ throw new Error('You are not running in OpenFin.');
+ }
+ connectSync() {
+ throw new Error('You are not running in OpenFin.');
+ }
+ send(data) {
+ throw new Error('You are not running in OpenFin.');
+ }
+ shutdown() {
+ throw new Error('You are not running in OpenFin.');
+ }
+ getPort() {
+ throw new Error('This transport has no port');
+ }
+ // eslint-disable-next-line no-useless-constructor
+ constructor() {
+ super();
+ }
+}
+mockWire.MockWire = MockWire;
+
+Object.defineProperty(mock, "__esModule", { value: true });
+exports.fin = mock.fin = void 0;
+const OpenFin = OpenFin$1;
+const fin_1 = fin$1;
+const transport_1 = transport;
+const mockEnvironment_1 = mockEnvironment;
+const mockWire_1 = mockWire;
+exports.fin = mock.fin = ((typeof window !== 'undefined' && window?.fin) ||
+ (() => {
+ const environment = new mockEnvironment_1.MockEnvironment();
+ const transport = new transport_1.Transport(mockWire_1.MockWire, environment, {
+ uuid: '',
+ name: ''
+ });
+ return new fin_1.Fin(transport);
+ })());
+var _default = mock.default = OpenFin;
+
+exports["default"] = _default;
+
+
+/***/ }),
+
+/***/ "../../node_modules/events/events.js":
+/*!*******************************************!*\
+ !*** ../../node_modules/events/events.js ***!
+ \*******************************************/
+/***/ ((module) => {
+
+"use strict";
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+var R = typeof Reflect === 'object' ? Reflect : null
+var ReflectApply = R && typeof R.apply === 'function'
+ ? R.apply
+ : function ReflectApply(target, receiver, args) {
+ return Function.prototype.apply.call(target, receiver, args);
+ }
+
+var ReflectOwnKeys
+if (R && typeof R.ownKeys === 'function') {
+ ReflectOwnKeys = R.ownKeys
+} else if (Object.getOwnPropertySymbols) {
+ ReflectOwnKeys = function ReflectOwnKeys(target) {
+ return Object.getOwnPropertyNames(target)
+ .concat(Object.getOwnPropertySymbols(target));
+ };
+} else {
+ ReflectOwnKeys = function ReflectOwnKeys(target) {
+ return Object.getOwnPropertyNames(target);
+ };
+}
+
+function ProcessEmitWarning(warning) {
+ if (console && console.warn) console.warn(warning);
+}
+
+var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
+ return value !== value;
+}
+
+function EventEmitter() {
+ EventEmitter.init.call(this);
+}
+module.exports = EventEmitter;
+module.exports.once = once;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._eventsCount = 0;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+var defaultMaxListeners = 10;
+
+function checkListener(listener) {
+ if (typeof listener !== 'function') {
+ throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
+ }
+}
+
+Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
+ enumerable: true,
+ get: function() {
+ return defaultMaxListeners;
+ },
+ set: function(arg) {
+ if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
+ throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
+ }
+ defaultMaxListeners = arg;
+ }
+});
+
+EventEmitter.init = function() {
+
+ if (this._events === undefined ||
+ this._events === Object.getPrototypeOf(this)._events) {
+ this._events = Object.create(null);
+ this._eventsCount = 0;
+ }
+
+ this._maxListeners = this._maxListeners || undefined;
+};
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
+ if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
+ throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
+ }
+ this._maxListeners = n;
+ return this;
+};
+
+function _getMaxListeners(that) {
+ if (that._maxListeners === undefined)
+ return EventEmitter.defaultMaxListeners;
+ return that._maxListeners;
+}
+
+EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
+ return _getMaxListeners(this);
+};
+
+EventEmitter.prototype.emit = function emit(type) {
+ var args = [];
+ for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
+ var doError = (type === 'error');
+
+ var events = this._events;
+ if (events !== undefined)
+ doError = (doError && events.error === undefined);
+ else if (!doError)
+ return false;
+
+ // If there is no 'error' event listener then throw.
+ if (doError) {
+ var er;
+ if (args.length > 0)
+ er = args[0];
+ if (er instanceof Error) {
+ // Note: The comments on the `throw` lines are intentional, they show
+ // up in Node's output if this results in an unhandled exception.
+ throw er; // Unhandled 'error' event
+ }
+ // At least give some kind of context to the user
+ var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
+ err.context = er;
+ throw err; // Unhandled 'error' event
+ }
+
+ var handler = events[type];
+
+ if (handler === undefined)
+ return false;
+
+ if (typeof handler === 'function') {
+ ReflectApply(handler, this, args);
+ } else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ ReflectApply(listeners[i], this, args);
+ }
+
+ return true;
+};
+
+function _addListener(target, type, listener, prepend) {
+ var m;
+ var events;
+ var existing;
+
+ checkListener(listener);
+
+ events = target._events;
+ if (events === undefined) {
+ events = target._events = Object.create(null);
+ target._eventsCount = 0;
+ } else {
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (events.newListener !== undefined) {
+ target.emit('newListener', type,
+ listener.listener ? listener.listener : listener);
+
+ // Re-assign `events` because a newListener handler could have caused the
+ // this._events to be assigned to a new object
+ events = target._events;
+ }
+ existing = events[type];
+ }
+
+ if (existing === undefined) {
+ // Optimize the case of one listener. Don't need the extra array object.
+ existing = events[type] = listener;
+ ++target._eventsCount;
+ } else {
+ if (typeof existing === 'function') {
+ // Adding the second element, need to change to array.
+ existing = events[type] =
+ prepend ? [listener, existing] : [existing, listener];
+ // If we've already got an array, just append.
+ } else if (prepend) {
+ existing.unshift(listener);
+ } else {
+ existing.push(listener);
+ }
+
+ // Check for listener leak
+ m = _getMaxListeners(target);
+ if (m > 0 && existing.length > m && !existing.warned) {
+ existing.warned = true;
+ // No error code for this since it is a Warning
+ // eslint-disable-next-line no-restricted-syntax
+ var w = new Error('Possible EventEmitter memory leak detected. ' +
+ existing.length + ' ' + String(type) + ' listeners ' +
+ 'added. Use emitter.setMaxListeners() to ' +
+ 'increase limit');
+ w.name = 'MaxListenersExceededWarning';
+ w.emitter = target;
+ w.type = type;
+ w.count = existing.length;
+ ProcessEmitWarning(w);
+ }
+ }
+
+ return target;
+}
+
+EventEmitter.prototype.addListener = function addListener(type, listener) {
+ return _addListener(this, type, listener, false);
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.prependListener =
+ function prependListener(type, listener) {
+ return _addListener(this, type, listener, true);
+ };
+
+function onceWrapper() {
+ if (!this.fired) {
+ this.target.removeListener(this.type, this.wrapFn);
+ this.fired = true;
+ if (arguments.length === 0)
+ return this.listener.call(this.target);
+ return this.listener.apply(this.target, arguments);
+ }
+}
+
+function _onceWrap(target, type, listener) {
+ var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
+ var wrapped = onceWrapper.bind(state);
+ wrapped.listener = listener;
+ state.wrapFn = wrapped;
+ return wrapped;
+}
+
+EventEmitter.prototype.once = function once(type, listener) {
+ checkListener(listener);
+ this.on(type, _onceWrap(this, type, listener));
+ return this;
+};
+
+EventEmitter.prototype.prependOnceListener =
+ function prependOnceListener(type, listener) {
+ checkListener(listener);
+ this.prependListener(type, _onceWrap(this, type, listener));
+ return this;
+ };
+
+// Emits a 'removeListener' event if and only if the listener was removed.
+EventEmitter.prototype.removeListener =
+ function removeListener(type, listener) {
+ var list, events, position, i, originalListener;
+
+ checkListener(listener);
+
+ events = this._events;
+ if (events === undefined)
+ return this;
+
+ list = events[type];
+ if (list === undefined)
+ return this;
+
+ if (list === listener || list.listener === listener) {
+ if (--this._eventsCount === 0)
+ this._events = Object.create(null);
+ else {
+ delete events[type];
+ if (events.removeListener)
+ this.emit('removeListener', type, list.listener || listener);
+ }
+ } else if (typeof list !== 'function') {
+ position = -1;
+
+ for (i = list.length - 1; i >= 0; i--) {
+ if (list[i] === listener || list[i].listener === listener) {
+ originalListener = list[i].listener;
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0)
+ return this;
+
+ if (position === 0)
+ list.shift();
+ else {
+ spliceOne(list, position);
+ }
+
+ if (list.length === 1)
+ events[type] = list[0];
+
+ if (events.removeListener !== undefined)
+ this.emit('removeListener', type, originalListener || listener);
+ }
+
+ return this;
+ };
+
+EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
+
+EventEmitter.prototype.removeAllListeners =
+ function removeAllListeners(type) {
+ var listeners, events, i;
+
+ events = this._events;
+ if (events === undefined)
+ return this;
+
+ // not listening for removeListener, no need to emit
+ if (events.removeListener === undefined) {
+ if (arguments.length === 0) {
+ this._events = Object.create(null);
+ this._eventsCount = 0;
+ } else if (events[type] !== undefined) {
+ if (--this._eventsCount === 0)
+ this._events = Object.create(null);
+ else
+ delete events[type];
+ }
+ return this;
+ }
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ var keys = Object.keys(events);
+ var key;
+ for (i = 0; i < keys.length; ++i) {
+ key = keys[i];
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
+ this._events = Object.create(null);
+ this._eventsCount = 0;
+ return this;
+ }
+
+ listeners = events[type];
+
+ if (typeof listeners === 'function') {
+ this.removeListener(type, listeners);
+ } else if (listeners !== undefined) {
+ // LIFO order
+ for (i = listeners.length - 1; i >= 0; i--) {
+ this.removeListener(type, listeners[i]);
+ }
+ }
+
+ return this;
+ };
+
+function _listeners(target, type, unwrap) {
+ var events = target._events;
+
+ if (events === undefined)
+ return [];
+
+ var evlistener = events[type];
+ if (evlistener === undefined)
+ return [];
+
+ if (typeof evlistener === 'function')
+ return unwrap ? [evlistener.listener || evlistener] : [evlistener];
+
+ return unwrap ?
+ unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
+}
+
+EventEmitter.prototype.listeners = function listeners(type) {
+ return _listeners(this, type, true);
+};
+
+EventEmitter.prototype.rawListeners = function rawListeners(type) {
+ return _listeners(this, type, false);
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+ if (typeof emitter.listenerCount === 'function') {
+ return emitter.listenerCount(type);
+ } else {
+ return listenerCount.call(emitter, type);
+ }
+};
+
+EventEmitter.prototype.listenerCount = listenerCount;
+function listenerCount(type) {
+ var events = this._events;
+
+ if (events !== undefined) {
+ var evlistener = events[type];
+
+ if (typeof evlistener === 'function') {
+ return 1;
+ } else if (evlistener !== undefined) {
+ return evlistener.length;
+ }
+ }
+
+ return 0;
+}
+
+EventEmitter.prototype.eventNames = function eventNames() {
+ return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
+};
+
+function arrayClone(arr, n) {
+ var copy = new Array(n);
+ for (var i = 0; i < n; ++i)
+ copy[i] = arr[i];
+ return copy;
+}
+
+function spliceOne(list, index) {
+ for (; index + 1 < list.length; index++)
+ list[index] = list[index + 1];
+ list.pop();
+}
+
+function unwrapListeners(arr) {
+ var ret = new Array(arr.length);
+ for (var i = 0; i < ret.length; ++i) {
+ ret[i] = arr[i].listener || arr[i];
+ }
+ return ret;
+}
+
+function once(emitter, name) {
+ return new Promise(function (resolve, reject) {
+ function errorListener(err) {
+ emitter.removeListener(name, resolver);
+ reject(err);
+ }
+
+ function resolver() {
+ if (typeof emitter.removeListener === 'function') {
+ emitter.removeListener('error', errorListener);
+ }
+ resolve([].slice.call(arguments));
+ };
+
+ eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
+ if (name !== 'error') {
+ addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
+ }
+ });
+}
+
+function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
+ if (typeof emitter.on === 'function') {
+ eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
+ }
+}
+
+function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
+ if (typeof emitter.on === 'function') {
+ if (flags.once) {
+ emitter.once(name, listener);
+ } else {
+ emitter.on(name, listener);
+ }
+ } else if (typeof emitter.addEventListener === 'function') {
+ // EventTarget does not have `error` event semantics like Node
+ // EventEmitters, we do not listen for `error` events here.
+ emitter.addEventListener(name, function wrapListener(arg) {
+ // IE does not have builtin `{ once: true }` support so we
+ // have to do it manually.
+ if (flags.once) {
+ emitter.removeEventListener(name, wrapListener);
+ }
+ listener(arg);
+ });
+ } else {
+ throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
+ }
+}
+
+
+/***/ }),
+
+/***/ "../../node_modules/lodash/lodash.js":
+/*!*******************************************!*\
+ !*** ../../node_modules/lodash/lodash.js ***!
+ \*******************************************/
+/***/ (function(module, exports, __webpack_require__) {
+
+/* module decorator */ module = __webpack_require__.nmd(module);
+var __WEBPACK_AMD_DEFINE_RESULT__;/**
+ * @license
+ * Lodash
+ * Copyright OpenJS Foundation and other contributors
+ * Released under MIT license
+ * Based on Underscore.js 1.8.3
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre-ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '4.17.21';
+
+ /** Used as the size to enable large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Error message constants. */
+ var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
+ FUNC_ERROR_TEXT = 'Expected a function',
+ INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`';
+
+ /** Used to stand-in for `undefined` hash values. */
+ var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+ /** Used as the maximum memoize cache size. */
+ var MAX_MEMOIZE_SIZE = 500;
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** Used to compose bitmasks for cloning. */
+ var CLONE_DEEP_FLAG = 1,
+ CLONE_FLAT_FLAG = 2,
+ CLONE_SYMBOLS_FLAG = 4;
+
+ /** Used to compose bitmasks for value comparisons. */
+ var COMPARE_PARTIAL_FLAG = 1,
+ COMPARE_UNORDERED_FLAG = 2;
+
+ /** Used to compose bitmasks for function metadata. */
+ var WRAP_BIND_FLAG = 1,
+ WRAP_BIND_KEY_FLAG = 2,
+ WRAP_CURRY_BOUND_FLAG = 4,
+ WRAP_CURRY_FLAG = 8,
+ WRAP_CURRY_RIGHT_FLAG = 16,
+ WRAP_PARTIAL_FLAG = 32,
+ WRAP_PARTIAL_RIGHT_FLAG = 64,
+ WRAP_ARY_FLAG = 128,
+ WRAP_REARG_FLAG = 256,
+ WRAP_FLIP_FLAG = 512;
+
+ /** Used as default options for `_.truncate`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect hot functions by number of calls within a span of milliseconds. */
+ var HOT_COUNT = 800,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 1,
+ LAZY_MAP_FLAG = 2,
+ LAZY_WHILE_FLAG = 3;
+
+ /** Used as references for various `Number` constants. */
+ var INFINITY = 1 / 0,
+ MAX_SAFE_INTEGER = 9007199254740991,
+ MAX_INTEGER = 1.7976931348623157e+308,
+ NAN = 0 / 0;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = 4294967295,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used to associate wrap methods with their bit flags. */
+ var wrapFlags = [
+ ['ary', WRAP_ARY_FLAG],
+ ['bind', WRAP_BIND_FLAG],
+ ['bindKey', WRAP_BIND_KEY_FLAG],
+ ['curry', WRAP_CURRY_FLAG],
+ ['curryRight', WRAP_CURRY_RIGHT_FLAG],
+ ['flip', WRAP_FLIP_FLAG],
+ ['partial', WRAP_PARTIAL_FLAG],
+ ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
+ ['rearg', WRAP_REARG_FLAG]
+ ];
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ asyncTag = '[object AsyncFunction]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ domExcTag = '[object DOMException]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ nullTag = '[object Null]',
+ objectTag = '[object Object]',
+ promiseTag = '[object Promise]',
+ proxyTag = '[object Proxy]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ symbolTag = '[object Symbol]',
+ undefinedTag = '[object Undefined]',
+ weakMapTag = '[object WeakMap]',
+ weakSetTag = '[object WeakSet]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ dataViewTag = '[object DataView]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
+ reUnescapedHtml = /[&<>"']/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /** Used to match property names within property paths. */
+ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+ reIsPlainProp = /^\w*$/,
+ rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
+
+ /**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
+ reHasRegExpChar = RegExp(reRegExpChar.source);
+
+ /** Used to match leading whitespace. */
+ var reTrimStart = /^\s+/;
+
+ /** Used to match a single whitespace character. */
+ var reWhitespace = /\s/;
+
+ /** Used to match wrap detail comments. */
+ var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
+ reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
+ reSplitDetails = /,? & /;
+
+ /** Used to match words composed of alphanumeric characters. */
+ var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
+
+ /**
+ * Used to validate the `validate` option in `_.template` variable.
+ *
+ * Forbids characters which could potentially change the meaning of the function argument definition:
+ * - "()," (modification of function parameters)
+ * - "=" (default value)
+ * - "[]{}" (destructuring of function parameters)
+ * - "/" (beginning of a comment)
+ * - whitespace
+ */
+ var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/;
+
+ /** Used to match backslashes in property paths. */
+ var reEscapeChar = /\\(\\)?/g;
+
+ /**
+ * Used to match
+ * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect bad signed hexadecimal string values. */
+ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+ /** Used to detect binary string values. */
+ var reIsBinary = /^0b[01]+$/i;
+
+ /** Used to detect host constructors (Safari). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to detect octal string values. */
+ var reIsOctal = /^0o[0-7]+$/i;
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /** Used to match Latin Unicode letters (excluding mathematical operators). */
+ var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to compose unicode character classes. */
+ var rsAstralRange = '\\ud800-\\udfff',
+ rsComboMarksRange = '\\u0300-\\u036f',
+ reComboHalfMarksRange = '\\ufe20-\\ufe2f',
+ rsComboSymbolsRange = '\\u20d0-\\u20ff',
+ rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
+ rsDingbatRange = '\\u2700-\\u27bf',
+ rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
+ rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
+ rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
+ rsPunctuationRange = '\\u2000-\\u206f',
+ rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
+ rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
+ rsVarRange = '\\ufe0e\\ufe0f',
+ rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
+
+ /** Used to compose unicode capture groups. */
+ var rsApos = "['\u2019]",
+ rsAstral = '[' + rsAstralRange + ']',
+ rsBreak = '[' + rsBreakRange + ']',
+ rsCombo = '[' + rsComboRange + ']',
+ rsDigits = '\\d+',
+ rsDingbat = '[' + rsDingbatRange + ']',
+ rsLower = '[' + rsLowerRange + ']',
+ rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
+ rsFitz = '\\ud83c[\\udffb-\\udfff]',
+ rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
+ rsNonAstral = '[^' + rsAstralRange + ']',
+ rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
+ rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
+ rsUpper = '[' + rsUpperRange + ']',
+ rsZWJ = '\\u200d';
+
+ /** Used to compose unicode regexes. */
+ var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
+ rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
+ rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
+ rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
+ reOptMod = rsModifier + '?',
+ rsOptVar = '[' + rsVarRange + ']?',
+ rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
+ rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
+ rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
+ rsSeq = rsOptVar + reOptMod + rsOptJoin,
+ rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
+ rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
+
+ /** Used to match apostrophes. */
+ var reApos = RegExp(rsApos, 'g');
+
+ /**
+ * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
+ * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
+ */
+ var reComboMark = RegExp(rsCombo, 'g');
+
+ /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
+ var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
+
+ /** Used to match complex or compound words. */
+ var reUnicodeWord = RegExp([
+ rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
+ rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
+ rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
+ rsUpper + '+' + rsOptContrUpper,
+ rsOrdUpper,
+ rsOrdLower,
+ rsDigits,
+ rsEmoji
+ ].join('|'), 'g');
+
+ /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
+ var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
+
+ /** Used to detect strings that need a more robust regexp to match words. */
+ var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
+ 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
+ typedArrayTags[errorTag] = typedArrayTags[funcTag] =
+ typedArrayTags[mapTag] = typedArrayTags[numberTag] =
+ typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
+ typedArrayTags[setTag] = typedArrayTags[stringTag] =
+ typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
+ cloneableTags[boolTag] = cloneableTags[dateTag] =
+ cloneableTags[float32Tag] = cloneableTags[float64Tag] =
+ cloneableTags[int8Tag] = cloneableTags[int16Tag] =
+ cloneableTags[int32Tag] = cloneableTags[mapTag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[setTag] =
+ cloneableTags[stringTag] = cloneableTags[symbolTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used to map Latin Unicode letters to basic Latin letters. */
+ var deburredLetters = {
+ // Latin-1 Supplement block.
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss',
+ // Latin Extended-A block.
+ '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
+ '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
+ '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
+ '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
+ '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
+ '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
+ '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
+ '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
+ '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
+ '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
+ '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
+ '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
+ '\u0134': 'J', '\u0135': 'j',
+ '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
+ '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
+ '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
+ '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
+ '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
+ '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
+ '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
+ '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
+ '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
+ '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
+ '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
+ '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
+ '\u0163': 't', '\u0165': 't', '\u0167': 't',
+ '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
+ '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
+ '\u0174': 'W', '\u0175': 'w',
+ '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
+ '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
+ '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
+ '\u0132': 'IJ', '\u0133': 'ij',
+ '\u0152': 'Oe', '\u0153': 'oe',
+ '\u0149': "'n", '\u017f': 's'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'"
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /** Built-in method references without a dependency on `root`. */
+ var freeParseFloat = parseFloat,
+ freeParseInt = parseInt;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = typeof __webpack_require__.g == 'object' && __webpack_require__.g && __webpack_require__.g.Object === Object && __webpack_require__.g;
+
+ /** Detect free variable `self`. */
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+ /** Used as a reference to the global object. */
+ var root = freeGlobal || freeSelf || Function('return this')();
+
+ /** Detect free variable `exports`. */
+ var freeExports = true && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = freeExports && "object" == 'object' && module && !module.nodeType && module;
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports;
+
+ /** Detect free variable `process` from Node.js. */
+ var freeProcess = moduleExports && freeGlobal.process;
+
+ /** Used to access faster Node.js helpers. */
+ var nodeUtil = (function() {
+ try {
+ // Use `util.types` for Node.js 10+.
+ var types = freeModule && freeModule.require && freeModule.require('util').types;
+
+ if (types) {
+ return types;
+ }
+
+ // Legacy `process.binding('util')` for Node.js < 10.
+ return freeProcess && freeProcess.binding && freeProcess.binding('util');
+ } catch (e) {}
+ }());
+
+ /* Node.js helper references. */
+ var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
+ nodeIsDate = nodeUtil && nodeUtil.isDate,
+ nodeIsMap = nodeUtil && nodeUtil.isMap,
+ nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
+ nodeIsSet = nodeUtil && nodeUtil.isSet,
+ nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * A faster alternative to `Function#apply`, this function invokes `func`
+ * with the `this` binding of `thisArg` and the arguments of `args`.
+ *
+ * @private
+ * @param {Function} func The function to invoke.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} args The arguments to invoke `func` with.
+ * @returns {*} Returns the result of `func`.
+ */
+ function apply(func, thisArg, args) {
+ switch (args.length) {
+ case 0: return func.call(thisArg);
+ case 1: return func.call(thisArg, args[0]);
+ case 2: return func.call(thisArg, args[0], args[1]);
+ case 3: return func.call(thisArg, args[0], args[1], args[2]);
+ }
+ return func.apply(thisArg, args);
+ }
+
+ /**
+ * A specialized version of `baseAggregator` for arrays.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} setter The function to set `accumulator` values.
+ * @param {Function} iteratee The iteratee to transform keys.
+ * @param {Object} accumulator The initial aggregated object.
+ * @returns {Function} Returns `accumulator`.
+ */
+ function arrayAggregator(array, setter, iteratee, accumulator) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ var value = array[index];
+ setter(accumulator, value, iteratee(value), array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array == null ? 0 : array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array == null ? 0 : array.length,
+ resIndex = 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[resIndex++] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.includes` for arrays without support for
+ * specifying an index to search from.
+ *
+ * @private
+ * @param {Array} [array] The array to inspect.
+ * @param {*} target The value to search for.
+ * @returns {boolean} Returns `true` if `target` is found, else `false`.
+ */
+ function arrayIncludes(array, value) {
+ var length = array == null ? 0 : array.length;
+ return !!length && baseIndexOf(array, value, 0) > -1;
+ }
+
+ /**
+ * This function is like `arrayIncludes` except that it accepts a comparator.
+ *
+ * @private
+ * @param {Array} [array] The array to inspect.
+ * @param {*} target The value to search for.
+ * @param {Function} comparator The comparator invoked per element.
+ * @returns {boolean} Returns `true` if `target` is found, else `false`.
+ */
+ function arrayIncludesWith(array, value, comparator) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ if (comparator(value, array[index])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for iteratee
+ * shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array == null ? 0 : array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * Appends the elements of `values` to `array`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to append.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayPush(array, values) {
+ var index = -1,
+ length = values.length,
+ offset = array.length;
+
+ while (++index < length) {
+ array[offset + index] = values[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initAccum] Specify using the first element of `array` as
+ * the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initAccum) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ if (initAccum && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initAccum] Specify using the last element of `array` as
+ * the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initAccum) {
+ var length = array == null ? 0 : array.length;
+ if (initAccum && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for iteratee
+ * shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the size of an ASCII `string`.
+ *
+ * @private
+ * @param {string} string The string inspect.
+ * @returns {number} Returns the string size.
+ */
+ var asciiSize = baseProperty('length');
+
+ /**
+ * Converts an ASCII `string` to an array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the converted array.
+ */
+ function asciiToArray(string) {
+ return string.split('');
+ }
+
+ /**
+ * Splits an ASCII `string` into an array of its words.
+ *
+ * @private
+ * @param {string} The string to inspect.
+ * @returns {Array} Returns the words of `string`.
+ */
+ function asciiWords(string) {
+ return string.match(reAsciiWord) || [];
+ }
+
+ /**
+ * The base implementation of methods like `_.findKey` and `_.findLastKey`,
+ * without support for iteratee shorthands, which iterates over `collection`
+ * using `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to inspect.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFindKey(collection, predicate, eachFunc) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = key;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.findIndex` and `_.findLastIndex` without
+ * support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {number} fromIndex The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseFindIndex(array, predicate, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromIndex + (fromRight ? 1 : -1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ return value === value
+ ? strictIndexOf(array, value, fromIndex)
+ : baseFindIndex(array, baseIsNaN, fromIndex);
+ }
+
+ /**
+ * This function is like `baseIndexOf` except that it accepts a comparator.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @param {Function} comparator The comparator invoked per element.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOfWith(array, value, fromIndex, comparator) {
+ var index = fromIndex - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (comparator(array[index], value)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.isNaN` without support for number objects.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ */
+ function baseIsNaN(value) {
+ return value !== value;
+ }
+
+ /**
+ * The base implementation of `_.mean` and `_.meanBy` without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {number} Returns the mean.
+ */
+ function baseMean(array, iteratee) {
+ var length = array == null ? 0 : array.length;
+ return length ? (baseSum(array, iteratee) / length) : NAN;
+ }
+
+ /**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.propertyOf` without support for deep paths.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function basePropertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight`, without support
+ * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initAccum Specify using the first or last element of
+ * `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initAccum
+ ? (initAccum = false, value)
+ : iteratee(accumulator, value, index, collection);
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` which uses `comparer` to define the
+ * sort order of `array` and replaces criteria objects with their corresponding
+ * values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.sum` and `_.sumBy` without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {number} Returns the sum.
+ */
+ function baseSum(array, iteratee) {
+ var result,
+ index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ var current = iteratee(array[index]);
+ if (current !== undefined) {
+ result = result === undefined ? current : (result + current);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
+ * of key-value pairs for `object` corresponding to the property names of `props`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the key-value pairs.
+ */
+ function baseToPairs(object, props) {
+ return arrayMap(props, function(key) {
+ return [key, object[key]];
+ });
+ }
+
+ /**
+ * The base implementation of `_.trim`.
+ *
+ * @private
+ * @param {string} string The string to trim.
+ * @returns {string} Returns the trimmed string.
+ */
+ function baseTrim(string) {
+ return string
+ ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
+ : string;
+ }
+
+ /**
+ * The base implementation of `_.unary` without support for storing metadata.
+ *
+ * @private
+ * @param {Function} func The function to cap arguments for.
+ * @returns {Function} Returns the new capped function.
+ */
+ function baseUnary(func) {
+ return function(value) {
+ return func(value);
+ };
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * of `props`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ return arrayMap(props, function(key) {
+ return object[key];
+ });
+ }
+
+ /**
+ * Checks if a `cache` value for `key` exists.
+ *
+ * @private
+ * @param {Object} cache The cache to query.
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function cacheHas(cache, key) {
+ return cache.has(key);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
+ * that is not found in the character symbols.
+ *
+ * @private
+ * @param {Array} strSymbols The string symbols to inspect.
+ * @param {Array} chrSymbols The character symbols to find.
+ * @returns {number} Returns the index of the first unmatched string symbol.
+ */
+ function charsStartIndex(strSymbols, chrSymbols) {
+ var index = -1,
+ length = strSymbols.length;
+
+ while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
+ * that is not found in the character symbols.
+ *
+ * @private
+ * @param {Array} strSymbols The string symbols to inspect.
+ * @param {Array} chrSymbols The character symbols to find.
+ * @returns {number} Returns the index of the last unmatched string symbol.
+ */
+ function charsEndIndex(strSymbols, chrSymbols) {
+ var index = strSymbols.length;
+
+ while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+ return index;
+ }
+
+ /**
+ * Gets the number of `placeholder` occurrences in `array`.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} placeholder The placeholder to search for.
+ * @returns {number} Returns the placeholder count.
+ */
+ function countHolders(array, placeholder) {
+ var length = array.length,
+ result = 0;
+
+ while (length--) {
+ if (array[length] === placeholder) {
+ ++result;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
+ * letters to basic Latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ var deburrLetter = basePropertyOf(deburredLetters);
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ var escapeHtmlChar = basePropertyOf(htmlEscapes);
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function getValue(object, key) {
+ return object == null ? undefined : object[key];
+ }
+
+ /**
+ * Checks if `string` contains Unicode symbols.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {boolean} Returns `true` if a symbol is found, else `false`.
+ */
+ function hasUnicode(string) {
+ return reHasUnicode.test(string);
+ }
+
+ /**
+ * Checks if `string` contains a word composed of Unicode symbols.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {boolean} Returns `true` if a word is found, else `false`.
+ */
+ function hasUnicodeWord(string) {
+ return reHasUnicodeWord.test(string);
+ }
+
+ /**
+ * Converts `iterator` to an array.
+ *
+ * @private
+ * @param {Object} iterator The iterator to convert.
+ * @returns {Array} Returns the converted array.
+ */
+ function iteratorToArray(iterator) {
+ var data,
+ result = [];
+
+ while (!(data = iterator.next()).done) {
+ result.push(data.value);
+ }
+ return result;
+ }
+
+ /**
+ * Converts `map` to its key-value pairs.
+ *
+ * @private
+ * @param {Object} map The map to convert.
+ * @returns {Array} Returns the key-value pairs.
+ */
+ function mapToArray(map) {
+ var index = -1,
+ result = Array(map.size);
+
+ map.forEach(function(value, key) {
+ result[++index] = [key, value];
+ });
+ return result;
+ }
+
+ /**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value === placeholder || value === PLACEHOLDER) {
+ array[index] = PLACEHOLDER;
+ result[resIndex++] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `set` to an array of its values.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the values.
+ */
+ function setToArray(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = value;
+ });
+ return result;
+ }
+
+ /**
+ * Converts `set` to its value-value pairs.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the value-value pairs.
+ */
+ function setToPairs(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = [value, value];
+ });
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.indexOf` which performs strict equality
+ * comparisons of values, i.e. `===`.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function strictIndexOf(array, value, fromIndex) {
+ var index = fromIndex - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * A specialized version of `_.lastIndexOf` which performs strict equality
+ * comparisons of values, i.e. `===`.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function strictLastIndexOf(array, value, fromIndex) {
+ var index = fromIndex + 1;
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Gets the number of symbols in `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the string size.
+ */
+ function stringSize(string) {
+ return hasUnicode(string)
+ ? unicodeSize(string)
+ : asciiSize(string);
+ }
+
+ /**
+ * Converts `string` to an array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the converted array.
+ */
+ function stringToArray(string) {
+ return hasUnicode(string)
+ ? unicodeToArray(string)
+ : asciiToArray(string);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedEndIndex(string) {
+ var index = string.length;
+
+ while (index-- && reWhitespace.test(string.charAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
+
+ /**
+ * Gets the size of a Unicode `string`.
+ *
+ * @private
+ * @param {string} string The string inspect.
+ * @returns {number} Returns the string size.
+ */
+ function unicodeSize(string) {
+ var result = reUnicode.lastIndex = 0;
+ while (reUnicode.test(string)) {
+ ++result;
+ }
+ return result;
+ }
+
+ /**
+ * Converts a Unicode `string` to an array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the converted array.
+ */
+ function unicodeToArray(string) {
+ return string.match(reUnicode) || [];
+ }
+
+ /**
+ * Splits a Unicode `string` into an array of its words.
+ *
+ * @private
+ * @param {string} The string to inspect.
+ * @returns {Array} Returns the words of `string`.
+ */
+ function unicodeWords(string) {
+ return string.match(reUnicodeWord) || [];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.1.0
+ * @category Util
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'foo': _.constant('foo') });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'bar': lodash.constant('bar') });
+ *
+ * _.isFunction(_.foo);
+ * // => true
+ * _.isFunction(_.bar);
+ * // => false
+ *
+ * lodash.isFunction(lodash.foo);
+ * // => false
+ * lodash.isFunction(lodash.bar);
+ * // => true
+ *
+ * // Create a suped-up `defer` in Node.js.
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ var runInContext = (function runInContext(context) {
+ context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
+
+ /** Built-in constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for built-in method references. */
+ var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect overreaching core-js shims. */
+ var coreJsData = context['__core-js_shared__'];
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /** Used to detect methods masquerading as native. */
+ var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+ }());
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var nativeObjectToString = objectProto.toString;
+
+ /** Used to infer the `Object` constructor. */
+ var objectCtorString = funcToString.call(Object);
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = root._;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Built-in value references. */
+ var Buffer = moduleExports ? context.Buffer : undefined,
+ Symbol = context.Symbol,
+ Uint8Array = context.Uint8Array,
+ allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
+ getPrototype = overArg(Object.getPrototypeOf, Object),
+ objectCreate = Object.create,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ splice = arrayProto.splice,
+ spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
+ symIterator = Symbol ? Symbol.iterator : undefined,
+ symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+ var defineProperty = (function() {
+ try {
+ var func = getNative(Object, 'defineProperty');
+ func({}, '', {});
+ return func;
+ } catch (e) {}
+ }());
+
+ /** Mocked built-ins. */
+ var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
+ ctxNow = Date && Date.now !== root.Date.now && Date.now,
+ ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeCeil = Math.ceil,
+ nativeFloor = Math.floor,
+ nativeGetSymbols = Object.getOwnPropertySymbols,
+ nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
+ nativeIsFinite = context.isFinite,
+ nativeJoin = arrayProto.join,
+ nativeKeys = overArg(Object.keys, Object),
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = Date.now,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random,
+ nativeReverse = arrayProto.reverse;
+
+ /* Built-in method references that are verified to be native. */
+ var DataView = getNative(context, 'DataView'),
+ Map = getNative(context, 'Map'),
+ Promise = getNative(context, 'Promise'),
+ Set = getNative(context, 'Set'),
+ WeakMap = getNative(context, 'WeakMap'),
+ nativeCreate = getNative(Object, 'create');
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /** Used to lookup unminified function names. */
+ var realNames = {};
+
+ /** Used to detect maps, sets, and weakmaps. */
+ var dataViewCtorString = toSource(DataView),
+ mapCtorString = toSource(Map),
+ promiseCtorString = toSource(Promise),
+ setCtorString = toSource(Set),
+ weakMapCtorString = toSource(WeakMap);
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
+ symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable implicit method
+ * chain sequences. Methods that operate on and return arrays, collections,
+ * and functions can be chained together. Methods that retrieve a single value
+ * or may return a primitive value will automatically end the chain sequence
+ * and return the unwrapped value. Otherwise, the value must be unwrapped
+ * with `_#value`.
+ *
+ * Explicit chain sequences, which must be unwrapped with `_#value`, may be
+ * enabled using `_.chain`.
+ *
+ * The execution of chained methods is lazy, that is, it's deferred until
+ * `_#value` is implicitly or explicitly called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion.
+ * Shortcut fusion is an optimization to merge iteratee calls; this avoids
+ * the creation of intermediate arrays and can greatly reduce the number of
+ * iteratee executions. Sections of a chain sequence qualify for shortcut
+ * fusion if the section is applied to an array and iteratees accept only
+ * one argument. The heuristic for whether a section qualifies for shortcut
+ * fusion is subject to change.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to lodash methods, wrappers have `Array` and `String` methods.
+ *
+ * The wrapper `Array` methods are:
+ * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
+ *
+ * The wrapper `String` methods are:
+ * `replace` and `split`
+ *
+ * The wrapper methods that support shortcut fusion are:
+ * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
+ * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
+ * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
+ *
+ * The chainable wrapper methods are:
+ * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
+ * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
+ * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
+ * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
+ * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
+ * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
+ * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
+ * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
+ * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
+ * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
+ * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
+ * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
+ * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
+ * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
+ * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
+ * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
+ * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
+ * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
+ * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
+ * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
+ * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
+ * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
+ * `zipObject`, `zipObjectDeep`, and `zipWith`
+ *
+ * The wrapper methods that are **not** chainable by default are:
+ * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
+ * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
+ * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
+ * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
+ * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
+ * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
+ * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
+ * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
+ * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
+ * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
+ * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
+ * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
+ * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
+ * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
+ * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
+ * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
+ * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
+ * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
+ * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
+ * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
+ * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
+ * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
+ * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
+ * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
+ * `upperFirst`, `value`, and `words`
+ *
+ * @name _
+ * @constructor
+ * @category Seq
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // Returns an unwrapped value.
+ * wrapped.reduce(_.add);
+ * // => 6
+ *
+ * // Returns a wrapped value.
+ * var squares = wrapped.map(square);
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return wrapperClone(value);
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} proto The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function object() {}
+ return function(proto) {
+ if (!isObject(proto)) {
+ return {};
+ }
+ if (objectCreate) {
+ return objectCreate(proto);
+ }
+ object.prototype = proto;
+ var result = new object;
+ object.prototype = undefined;
+ return result;
+ };
+ }());
+
+ /**
+ * The function whose prototype chain sequence wrappers inherit from.
+ *
+ * @private
+ */
+ function baseLodash() {
+ // No operation performed.
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable explicit method chain sequences.
+ */
+ function LodashWrapper(value, chainAll) {
+ this.__wrapped__ = value;
+ this.__actions__ = [];
+ this.__chain__ = !!chainAll;
+ this.__index__ = 0;
+ this.__values__ = undefined;
+ }
+
+ /**
+ * By default, the template delimiters used by lodash are like those in
+ * embedded Ruby (ERB) as well as ES2015 template strings. Change the
+ * following template settings to use alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type {Object}
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type {RegExp}
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type {RegExp}
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type {RegExp}
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type {string}
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type {Object}
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type {Function}
+ */
+ '_': lodash
+ }
+ };
+
+ // Ensure wrappers are instances of `baseLodash`.
+ lodash.prototype = baseLodash.prototype;
+ lodash.prototype.constructor = lodash;
+
+ LodashWrapper.prototype = baseCreate(baseLodash.prototype);
+ LodashWrapper.prototype.constructor = LodashWrapper;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @constructor
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.__wrapped__ = value;
+ this.__actions__ = [];
+ this.__dir__ = 1;
+ this.__filtered__ = false;
+ this.__iteratees__ = [];
+ this.__takeCount__ = MAX_ARRAY_LENGTH;
+ this.__views__ = [];
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var result = new LazyWrapper(this.__wrapped__);
+ result.__actions__ = copyArray(this.__actions__);
+ result.__dir__ = this.__dir__;
+ result.__filtered__ = this.__filtered__;
+ result.__iteratees__ = copyArray(this.__iteratees__);
+ result.__takeCount__ = this.__takeCount__;
+ result.__views__ = copyArray(this.__views__);
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ if (this.__filtered__) {
+ var result = new LazyWrapper(this);
+ result.__dir__ = -1;
+ result.__filtered__ = true;
+ } else {
+ result = this.clone();
+ result.__dir__ *= -1;
+ }
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.__wrapped__.value(),
+ dir = this.__dir__,
+ isArr = isArray(array),
+ isRight = dir < 0,
+ arrLength = isArr ? array.length : 0,
+ view = getView(0, arrLength, this.__views__),
+ start = view.start,
+ end = view.end,
+ length = end - start,
+ index = isRight ? end : (start - 1),
+ iteratees = this.__iteratees__,
+ iterLength = iteratees.length,
+ resIndex = 0,
+ takeCount = nativeMin(length, this.__takeCount__);
+
+ if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
+ return baseWrapperValue(array, this.__actions__);
+ }
+ var result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ type = data.type,
+ computed = iteratee(value);
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ result[resIndex++] = value;
+ }
+ return result;
+ }
+
+ // Ensure `LazyWrapper` is an instance of `baseLodash`.
+ LazyWrapper.prototype = baseCreate(baseLodash.prototype);
+ LazyWrapper.prototype.constructor = LazyWrapper;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Hash(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+ function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ this.size = 0;
+ }
+
+ /**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function hashDelete(key) {
+ var result = this.has(key) && delete this.__data__[key];
+ this.size -= result ? 1 : 0;
+ return result;
+ }
+
+ /**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ }
+
+ /**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
+ }
+
+ /**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+ function hashSet(key, value) {
+ var data = this.__data__;
+ this.size += this.has(key) ? 0 : 1;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+ }
+
+ // Add methods to `Hash`.
+ Hash.prototype.clear = hashClear;
+ Hash.prototype['delete'] = hashDelete;
+ Hash.prototype.get = hashGet;
+ Hash.prototype.has = hashHas;
+ Hash.prototype.set = hashSet;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function ListCache(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+ function listCacheClear() {
+ this.__data__ = [];
+ this.size = 0;
+ }
+
+ /**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ --this.size;
+ return true;
+ }
+
+ /**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+ }
+
+ /**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+ }
+
+ /**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+ function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ ++this.size;
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+ }
+
+ // Add methods to `ListCache`.
+ ListCache.prototype.clear = listCacheClear;
+ ListCache.prototype['delete'] = listCacheDelete;
+ ListCache.prototype.get = listCacheGet;
+ ListCache.prototype.has = listCacheHas;
+ ListCache.prototype.set = listCacheSet;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function MapCache(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+ function mapCacheClear() {
+ this.size = 0;
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+ }
+
+ /**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function mapCacheDelete(key) {
+ var result = getMapData(this, key)['delete'](key);
+ this.size -= result ? 1 : 0;
+ return result;
+ }
+
+ /**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+ }
+
+ /**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+ }
+
+ /**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+ function mapCacheSet(key, value) {
+ var data = getMapData(this, key),
+ size = data.size;
+
+ data.set(key, value);
+ this.size += data.size == size ? 0 : 1;
+ return this;
+ }
+
+ // Add methods to `MapCache`.
+ MapCache.prototype.clear = mapCacheClear;
+ MapCache.prototype['delete'] = mapCacheDelete;
+ MapCache.prototype.get = mapCacheGet;
+ MapCache.prototype.has = mapCacheHas;
+ MapCache.prototype.set = mapCacheSet;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates an array cache object to store unique values.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var index = -1,
+ length = values == null ? 0 : values.length;
+
+ this.__data__ = new MapCache;
+ while (++index < length) {
+ this.add(values[index]);
+ }
+ }
+
+ /**
+ * Adds `value` to the array cache.
+ *
+ * @private
+ * @name add
+ * @memberOf SetCache
+ * @alias push
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache instance.
+ */
+ function setCacheAdd(value) {
+ this.__data__.set(value, HASH_UNDEFINED);
+ return this;
+ }
+
+ /**
+ * Checks if `value` is in the array cache.
+ *
+ * @private
+ * @name has
+ * @memberOf SetCache
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `true` if `value` is found, else `false`.
+ */
+ function setCacheHas(value) {
+ return this.__data__.has(value);
+ }
+
+ // Add methods to `SetCache`.
+ SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
+ SetCache.prototype.has = setCacheHas;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a stack cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Stack(entries) {
+ var data = this.__data__ = new ListCache(entries);
+ this.size = data.size;
+ }
+
+ /**
+ * Removes all key-value entries from the stack.
+ *
+ * @private
+ * @name clear
+ * @memberOf Stack
+ */
+ function stackClear() {
+ this.__data__ = new ListCache;
+ this.size = 0;
+ }
+
+ /**
+ * Removes `key` and its value from the stack.
+ *
+ * @private
+ * @name delete
+ * @memberOf Stack
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function stackDelete(key) {
+ var data = this.__data__,
+ result = data['delete'](key);
+
+ this.size = data.size;
+ return result;
+ }
+
+ /**
+ * Gets the stack value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Stack
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function stackGet(key) {
+ return this.__data__.get(key);
+ }
+
+ /**
+ * Checks if a stack value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Stack
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function stackHas(key) {
+ return this.__data__.has(key);
+ }
+
+ /**
+ * Sets the stack `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Stack
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the stack cache instance.
+ */
+ function stackSet(key, value) {
+ var data = this.__data__;
+ if (data instanceof ListCache) {
+ var pairs = data.__data__;
+ if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+ pairs.push([key, value]);
+ this.size = ++data.size;
+ return this;
+ }
+ data = this.__data__ = new MapCache(pairs);
+ }
+ data.set(key, value);
+ this.size = data.size;
+ return this;
+ }
+
+ // Add methods to `Stack`.
+ Stack.prototype.clear = stackClear;
+ Stack.prototype['delete'] = stackDelete;
+ Stack.prototype.get = stackGet;
+ Stack.prototype.has = stackHas;
+ Stack.prototype.set = stackSet;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+ function arrayLikeKeys(value, inherited) {
+ var isArr = isArray(value),
+ isArg = !isArr && isArguments(value),
+ isBuff = !isArr && !isArg && isBuffer(value),
+ isType = !isArr && !isArg && !isBuff && isTypedArray(value),
+ skipIndexes = isArr || isArg || isBuff || isType,
+ result = skipIndexes ? baseTimes(value.length, String) : [],
+ length = result.length;
+
+ for (var key in value) {
+ if ((inherited || hasOwnProperty.call(value, key)) &&
+ !(skipIndexes && (
+ // Safari 9 has enumerable `arguments.length` in strict mode.
+ key == 'length' ||
+ // Node.js 0.10 has enumerable non-index properties on buffers.
+ (isBuff && (key == 'offset' || key == 'parent')) ||
+ // PhantomJS 2 has enumerable non-index properties on typed arrays.
+ (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
+ // Skip index properties.
+ isIndex(key, length)
+ ))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.sample` for arrays.
+ *
+ * @private
+ * @param {Array} array The array to sample.
+ * @returns {*} Returns the random element.
+ */
+ function arraySample(array) {
+ var length = array.length;
+ return length ? array[baseRandom(0, length - 1)] : undefined;
+ }
+
+ /**
+ * A specialized version of `_.sampleSize` for arrays.
+ *
+ * @private
+ * @param {Array} array The array to sample.
+ * @param {number} n The number of elements to sample.
+ * @returns {Array} Returns the random elements.
+ */
+ function arraySampleSize(array, n) {
+ return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
+ }
+
+ /**
+ * A specialized version of `_.shuffle` for arrays.
+ *
+ * @private
+ * @param {Array} array The array to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ */
+ function arrayShuffle(array) {
+ return shuffleSelf(copyArray(array));
+ }
+
+ /**
+ * This function is like `assignValue` except that it doesn't assign
+ * `undefined` values.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function assignMergeValue(object, key, value) {
+ if ((value !== undefined && !eq(object[key], value)) ||
+ (value === undefined && !(key in object))) {
+ baseAssignValue(object, key, value);
+ }
+ }
+
+ /**
+ * Assigns `value` to `key` of `object` if the existing value is not equivalent
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function assignValue(object, key, value) {
+ var objValue = object[key];
+ if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+ (value === undefined && !(key in object))) {
+ baseAssignValue(object, key, value);
+ }
+ }
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Aggregates elements of `collection` on `accumulator` with keys transformed
+ * by `iteratee` and values set by `setter`.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} setter The function to set `accumulator` values.
+ * @param {Function} iteratee The iteratee to transform keys.
+ * @param {Object} accumulator The initial aggregated object.
+ * @returns {Function} Returns `accumulator`.
+ */
+ function baseAggregator(collection, setter, iteratee, accumulator) {
+ baseEach(collection, function(value, key, collection) {
+ setter(accumulator, value, iteratee(value), collection);
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssign(object, source) {
+ return object && copyObject(source, keys(source), object);
+ }
+
+ /**
+ * The base implementation of `_.assignIn` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssignIn(object, source) {
+ return object && copyObject(source, keysIn(source), object);
+ }
+
+ /**
+ * The base implementation of `assignValue` and `assignMergeValue` without
+ * value checks.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function baseAssignValue(object, key, value) {
+ if (key == '__proto__' && defineProperty) {
+ defineProperty(object, key, {
+ 'configurable': true,
+ 'enumerable': true,
+ 'value': value,
+ 'writable': true
+ });
+ } else {
+ object[key] = value;
+ }
+ }
+
+ /**
+ * The base implementation of `_.at` without support for individual paths.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {string[]} paths The property paths to pick.
+ * @returns {Array} Returns the picked elements.
+ */
+ function baseAt(object, paths) {
+ var index = -1,
+ length = paths.length,
+ result = Array(length),
+ skip = object == null;
+
+ while (++index < length) {
+ result[index] = skip ? undefined : get(object, paths[index]);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.clamp` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {number} number The number to clamp.
+ * @param {number} [lower] The lower bound.
+ * @param {number} upper The upper bound.
+ * @returns {number} Returns the clamped number.
+ */
+ function baseClamp(number, lower, upper) {
+ if (number === number) {
+ if (upper !== undefined) {
+ number = number <= upper ? number : upper;
+ }
+ if (lower !== undefined) {
+ number = number >= lower ? number : lower;
+ }
+ }
+ return number;
+ }
+
+ /**
+ * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+ * traversed objects.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} bitmask The bitmask flags.
+ * 1 - Deep clone
+ * 2 - Flatten inherited properties
+ * 4 - Clone symbols
+ * @param {Function} [customizer] The function to customize cloning.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The parent object of `value`.
+ * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, bitmask, customizer, key, object, stack) {
+ var result,
+ isDeep = bitmask & CLONE_DEEP_FLAG,
+ isFlat = bitmask & CLONE_FLAT_FLAG,
+ isFull = bitmask & CLONE_SYMBOLS_FLAG;
+
+ if (customizer) {
+ result = object ? customizer(value, key, object, stack) : customizer(value);
+ }
+ if (result !== undefined) {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return copyArray(value, result);
+ }
+ } else {
+ var tag = getTag(value),
+ isFunc = tag == funcTag || tag == genTag;
+
+ if (isBuffer(value)) {
+ return cloneBuffer(value, isDeep);
+ }
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = (isFlat || isFunc) ? {} : initCloneObject(value);
+ if (!isDeep) {
+ return isFlat
+ ? copySymbolsIn(value, baseAssignIn(result, value))
+ : copySymbols(value, baseAssign(result, value));
+ }
+ } else {
+ if (!cloneableTags[tag]) {
+ return object ? value : {};
+ }
+ result = initCloneByTag(value, tag, isDeep);
+ }
+ }
+ // Check for circular references and return its corresponding clone.
+ stack || (stack = new Stack);
+ var stacked = stack.get(value);
+ if (stacked) {
+ return stacked;
+ }
+ stack.set(value, result);
+
+ if (isSet(value)) {
+ value.forEach(function(subValue) {
+ result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
+ });
+ } else if (isMap(value)) {
+ value.forEach(function(subValue, key) {
+ result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
+ });
+ }
+
+ var keysFunc = isFull
+ ? (isFlat ? getAllKeysIn : getAllKeys)
+ : (isFlat ? keysIn : keys);
+
+ var props = isArr ? undefined : keysFunc(value);
+ arrayEach(props || value, function(subValue, key) {
+ if (props) {
+ key = subValue;
+ subValue = value[key];
+ }
+ // Recursively populate clone (susceptible to call stack limits).
+ assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.conforms` which doesn't clone `source`.
+ *
+ * @private
+ * @param {Object} source The object of property predicates to conform to.
+ * @returns {Function} Returns the new spec function.
+ */
+ function baseConforms(source) {
+ var props = keys(source);
+ return function(object) {
+ return baseConformsTo(object, source, props);
+ };
+ }
+
+ /**
+ * The base implementation of `_.conformsTo` which accepts `props` to check.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Object} source The object of property predicates to conform to.
+ * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+ */
+ function baseConformsTo(object, source, props) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ object = Object(object);
+ while (length--) {
+ var key = props[length],
+ predicate = source[key],
+ value = object[key];
+
+ if ((value === undefined && !(key in object)) || !predicate(value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts `args`
+ * to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Array} args The arguments to provide to `func`.
+ * @returns {number|Object} Returns the timer id or timeout object.
+ */
+ function baseDelay(func, wait, args) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
+ }
+
+ /**
+ * The base implementation of methods like `_.difference` without support
+ * for excluding multiple arrays or iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values, iteratee, comparator) {
+ var index = -1,
+ includes = arrayIncludes,
+ isCommon = true,
+ length = array.length,
+ result = [],
+ valuesLength = values.length;
+
+ if (!length) {
+ return result;
+ }
+ if (iteratee) {
+ values = arrayMap(values, baseUnary(iteratee));
+ }
+ if (comparator) {
+ includes = arrayIncludesWith;
+ isCommon = false;
+ }
+ else if (values.length >= LARGE_ARRAY_SIZE) {
+ includes = cacheHas;
+ isCommon = false;
+ values = new SetCache(values);
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee == null ? value : iteratee(value);
+
+ value = (comparator || value !== 0) ? value : 0;
+ if (isCommon && computed === computed) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === computed) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (!includes(values, computed, comparator)) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object} Returns `collection`.
+ */
+ var baseEach = createBaseEach(baseForOwn);
+
+ /**
+ * The base implementation of `_.forEachRight` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object} Returns `collection`.
+ */
+ var baseEachRight = createBaseEach(baseForOwnRight, true);
+
+ /**
+ * The base implementation of `_.every` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of methods like `_.max` and `_.min` which accepts a
+ * `comparator` to determine the extremum value.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The iteratee invoked per iteration.
+ * @param {Function} comparator The comparator used to compare values.
+ * @returns {*} Returns the extremum value.
+ */
+ function baseExtremum(array, iteratee, comparator) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ var value = array[index],
+ current = iteratee(value);
+
+ if (current != null && (computed === undefined
+ ? (current === current && !isSymbol(current))
+ : comparator(current, computed)
+ )) {
+ var computed = current,
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.fill` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to fill.
+ * @param {*} value The value to fill `array` with.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns `array`.
+ */
+ function baseFill(array, value, start, end) {
+ var length = array.length;
+
+ start = toInteger(start);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (end === undefined || end > length) ? length : toInteger(end);
+ if (end < 0) {
+ end += length;
+ }
+ end = start > end ? 0 : toLength(end);
+ while (start < end) {
+ array[start++] = value;
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with support for restricting flattening.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {number} depth The maximum recursion depth.
+ * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
+ * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
+ * @param {Array} [result=[]] The initial result value.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, depth, predicate, isStrict, result) {
+ var index = -1,
+ length = array.length;
+
+ predicate || (predicate = isFlattenable);
+ result || (result = []);
+
+ while (++index < length) {
+ var value = array[index];
+ if (depth > 0 && predicate(value)) {
+ if (depth > 1) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ baseFlatten(value, depth - 1, predicate, isStrict, result);
+ } else {
+ arrayPush(result, value);
+ }
+ } else if (!isStrict) {
+ result[result.length] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForOwn` which iterates over `object`
+ * properties returned by `keysFunc` and invokes `iteratee` for each property.
+ * Iteratee functions may exit iteration early by explicitly returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ var baseFor = createBaseFor();
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ var baseForRight = createBaseFor(true);
+
+ /**
+ * The base implementation of `_.forOwn` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return object && baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return object && baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from `props`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the function names.
+ */
+ function baseFunctions(object, props) {
+ return arrayFilter(props, function(key) {
+ return isFunction(object[key]);
+ });
+ }
+
+ /**
+ * The base implementation of `_.get` without support for default values.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to get.
+ * @returns {*} Returns the resolved value.
+ */
+ function baseGet(object, path) {
+ path = castPath(path, object);
+
+ var index = 0,
+ length = path.length;
+
+ while (object != null && index < length) {
+ object = object[toKey(path[index++])];
+ }
+ return (index && index == length) ? object : undefined;
+ }
+
+ /**
+ * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+ * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @param {Function} symbolsFunc The function to get the symbols of `object`.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+ var result = keysFunc(object);
+ return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+ }
+
+ /**
+ * The base implementation of `getTag` without fallbacks for buggy environments.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ function baseGetTag(value) {
+ if (value == null) {
+ return value === undefined ? undefinedTag : nullTag;
+ }
+ return (symToStringTag && symToStringTag in Object(value))
+ ? getRawTag(value)
+ : objectToString(value);
+ }
+
+ /**
+ * The base implementation of `_.gt` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is greater than `other`,
+ * else `false`.
+ */
+ function baseGt(value, other) {
+ return value > other;
+ }
+
+ /**
+ * The base implementation of `_.has` without support for deep paths.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {Array|string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` exists, else `false`.
+ */
+ function baseHas(object, key) {
+ return object != null && hasOwnProperty.call(object, key);
+ }
+
+ /**
+ * The base implementation of `_.hasIn` without support for deep paths.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {Array|string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` exists, else `false`.
+ */
+ function baseHasIn(object, key) {
+ return object != null && key in Object(object);
+ }
+
+ /**
+ * The base implementation of `_.inRange` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {number} number The number to check.
+ * @param {number} start The start of the range.
+ * @param {number} end The end of the range.
+ * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+ */
+ function baseInRange(number, start, end) {
+ return number >= nativeMin(start, end) && number < nativeMax(start, end);
+ }
+
+ /**
+ * The base implementation of methods like `_.intersection`, without support
+ * for iteratee shorthands, that accepts an array of arrays to inspect.
+ *
+ * @private
+ * @param {Array} arrays The arrays to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of shared values.
+ */
+ function baseIntersection(arrays, iteratee, comparator) {
+ var includes = comparator ? arrayIncludesWith : arrayIncludes,
+ length = arrays[0].length,
+ othLength = arrays.length,
+ othIndex = othLength,
+ caches = Array(othLength),
+ maxLength = Infinity,
+ result = [];
+
+ while (othIndex--) {
+ var array = arrays[othIndex];
+ if (othIndex && iteratee) {
+ array = arrayMap(array, baseUnary(iteratee));
+ }
+ maxLength = nativeMin(array.length, maxLength);
+ caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
+ ? new SetCache(othIndex && array)
+ : undefined;
+ }
+ array = arrays[0];
+
+ var index = -1,
+ seen = caches[0];
+
+ outer:
+ while (++index < length && result.length < maxLength) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value) : value;
+
+ value = (comparator || value !== 0) ? value : 0;
+ if (!(seen
+ ? cacheHas(seen, computed)
+ : includes(result, computed, comparator)
+ )) {
+ othIndex = othLength;
+ while (--othIndex) {
+ var cache = caches[othIndex];
+ if (!(cache
+ ? cacheHas(cache, computed)
+ : includes(arrays[othIndex], computed, comparator))
+ ) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.invert` and `_.invertBy` which inverts
+ * `object` with values transformed by `iteratee` and set by `setter`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} setter The function to set `accumulator` values.
+ * @param {Function} iteratee The iteratee to transform values.
+ * @param {Object} accumulator The initial inverted object.
+ * @returns {Function} Returns `accumulator`.
+ */
+ function baseInverter(object, setter, iteratee, accumulator) {
+ baseForOwn(object, function(value, key, object) {
+ setter(accumulator, iteratee(value), key, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `_.invoke` without support for individual
+ * method arguments.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the method to invoke.
+ * @param {Array} args The arguments to invoke the method with.
+ * @returns {*} Returns the result of the invoked method.
+ */
+ function baseInvoke(object, path, args) {
+ path = castPath(path, object);
+ object = parent(object, path);
+ var func = object == null ? object : object[toKey(last(path))];
+ return func == null ? undefined : apply(func, object, args);
+ }
+
+ /**
+ * The base implementation of `_.isArguments`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ */
+ function baseIsArguments(value) {
+ return isObjectLike(value) && baseGetTag(value) == argsTag;
+ }
+
+ /**
+ * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+ */
+ function baseIsArrayBuffer(value) {
+ return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
+ }
+
+ /**
+ * The base implementation of `_.isDate` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+ */
+ function baseIsDate(value) {
+ return isObjectLike(value) && baseGetTag(value) == dateTag;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` which supports partial comparisons
+ * and tracks traversed objects.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {boolean} bitmask The bitmask flags.
+ * 1 - Unordered comparison
+ * 2 - Partial comparison
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, bitmask, customizer, stack) {
+ if (value === other) {
+ return true;
+ }
+ if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = objIsArr ? arrayTag : getTag(object),
+ othTag = othIsArr ? arrayTag : getTag(other);
+
+ objTag = objTag == argsTag ? objectTag : objTag;
+ othTag = othTag == argsTag ? objectTag : othTag;
+
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && isBuffer(object)) {
+ if (!isBuffer(other)) {
+ return false;
+ }
+ objIsArr = true;
+ objIsObj = false;
+ }
+ if (isSameTag && !objIsObj) {
+ stack || (stack = new Stack);
+ return (objIsArr || isTypedArray(object))
+ ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
+ : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
+ }
+ if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
+ var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (objIsWrapped || othIsWrapped) {
+ var objUnwrapped = objIsWrapped ? object.value() : object,
+ othUnwrapped = othIsWrapped ? other.value() : other;
+
+ stack || (stack = new Stack);
+ return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
+ }
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ stack || (stack = new Stack);
+ return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
+ }
+
+ /**
+ * The base implementation of `_.isMap` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+ */
+ function baseIsMap(value) {
+ return isObjectLike(value) && getTag(value) == mapTag;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Array} matchData The property names, values, and compare flags to match.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, source, matchData, customizer) {
+ var index = matchData.length,
+ length = index,
+ noCustomizer = !customizer;
+
+ if (object == null) {
+ return !length;
+ }
+ object = Object(object);
+ while (index--) {
+ var data = matchData[index];
+ if ((noCustomizer && data[2])
+ ? data[1] !== object[data[0]]
+ : !(data[0] in object)
+ ) {
+ return false;
+ }
+ }
+ while (++index < length) {
+ data = matchData[index];
+ var key = data[0],
+ objValue = object[key],
+ srcValue = data[1];
+
+ if (noCustomizer && data[2]) {
+ if (objValue === undefined && !(key in object)) {
+ return false;
+ }
+ } else {
+ var stack = new Stack;
+ if (customizer) {
+ var result = customizer(objValue, srcValue, key, object, source, stack);
+ }
+ if (!(result === undefined
+ ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
+ : result
+ )) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+ function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+ }
+
+ /**
+ * The base implementation of `_.isRegExp` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+ */
+ function baseIsRegExp(value) {
+ return isObjectLike(value) && baseGetTag(value) == regexpTag;
+ }
+
+ /**
+ * The base implementation of `_.isSet` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+ */
+ function baseIsSet(value) {
+ return isObjectLike(value) && getTag(value) == setTag;
+ }
+
+ /**
+ * The base implementation of `_.isTypedArray` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ */
+ function baseIsTypedArray(value) {
+ return isObjectLike(value) &&
+ isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
+ }
+
+ /**
+ * The base implementation of `_.iteratee`.
+ *
+ * @private
+ * @param {*} [value=_.identity] The value to convert to an iteratee.
+ * @returns {Function} Returns the iteratee.
+ */
+ function baseIteratee(value) {
+ // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
+ // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
+ if (typeof value == 'function') {
+ return value;
+ }
+ if (value == null) {
+ return identity;
+ }
+ if (typeof value == 'object') {
+ return isArray(value)
+ ? baseMatchesProperty(value[0], value[1])
+ : baseMatches(value);
+ }
+ return property(value);
+ }
+
+ /**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ if (!isPrototype(object)) {
+ return nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeysIn(object) {
+ if (!isObject(object)) {
+ return nativeKeysIn(object);
+ }
+ var isProto = isPrototype(object),
+ result = [];
+
+ for (var key in object) {
+ if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.lt` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if `value` is less than `other`,
+ * else `false`.
+ */
+ function baseLt(value, other) {
+ return value < other;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var index = -1,
+ result = isArrayLike(collection) ? Array(collection.length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = iteratee(value, key, collection);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which doesn't clone `source`.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function baseMatches(source) {
+ var matchData = getMatchData(source);
+ if (matchData.length == 1 && matchData[0][2]) {
+ return matchesStrictComparable(matchData[0][0], matchData[0][1]);
+ }
+ return function(object) {
+ return object === source || baseIsMatch(object, source, matchData);
+ };
+ }
+
+ /**
+ * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
+ *
+ * @private
+ * @param {string} path The path of the property to get.
+ * @param {*} srcValue The value to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function baseMatchesProperty(path, srcValue) {
+ if (isKey(path) && isStrictComparable(srcValue)) {
+ return matchesStrictComparable(toKey(path), srcValue);
+ }
+ return function(object) {
+ var objValue = get(object, path);
+ return (objValue === undefined && objValue === srcValue)
+ ? hasIn(object, path)
+ : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for multiple sources.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {number} srcIndex The index of `source`.
+ * @param {Function} [customizer] The function to customize merged values.
+ * @param {Object} [stack] Tracks traversed source values and their merged
+ * counterparts.
+ */
+ function baseMerge(object, source, srcIndex, customizer, stack) {
+ if (object === source) {
+ return;
+ }
+ baseFor(source, function(srcValue, key) {
+ stack || (stack = new Stack);
+ if (isObject(srcValue)) {
+ baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
+ }
+ else {
+ var newValue = customizer
+ ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
+ : undefined;
+
+ if (newValue === undefined) {
+ newValue = srcValue;
+ }
+ assignMergeValue(object, key, newValue);
+ }
+ }, keysIn);
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {number} srcIndex The index of `source`.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {Object} [stack] Tracks traversed source values and their merged
+ * counterparts.
+ */
+ function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
+ var objValue = safeGet(object, key),
+ srcValue = safeGet(source, key),
+ stacked = stack.get(srcValue);
+
+ if (stacked) {
+ assignMergeValue(object, key, stacked);
+ return;
+ }
+ var newValue = customizer
+ ? customizer(objValue, srcValue, (key + ''), object, source, stack)
+ : undefined;
+
+ var isCommon = newValue === undefined;
+
+ if (isCommon) {
+ var isArr = isArray(srcValue),
+ isBuff = !isArr && isBuffer(srcValue),
+ isTyped = !isArr && !isBuff && isTypedArray(srcValue);
+
+ newValue = srcValue;
+ if (isArr || isBuff || isTyped) {
+ if (isArray(objValue)) {
+ newValue = objValue;
+ }
+ else if (isArrayLikeObject(objValue)) {
+ newValue = copyArray(objValue);
+ }
+ else if (isBuff) {
+ isCommon = false;
+ newValue = cloneBuffer(srcValue, true);
+ }
+ else if (isTyped) {
+ isCommon = false;
+ newValue = cloneTypedArray(srcValue, true);
+ }
+ else {
+ newValue = [];
+ }
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ newValue = objValue;
+ if (isArguments(objValue)) {
+ newValue = toPlainObject(objValue);
+ }
+ else if (!isObject(objValue) || isFunction(objValue)) {
+ newValue = initCloneObject(srcValue);
+ }
+ }
+ else {
+ isCommon = false;
+ }
+ }
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ stack.set(srcValue, newValue);
+ mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
+ stack['delete'](srcValue);
+ }
+ assignMergeValue(object, key, newValue);
+ }
+
+ /**
+ * The base implementation of `_.nth` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {Array} array The array to query.
+ * @param {number} n The index of the element to return.
+ * @returns {*} Returns the nth element of `array`.
+ */
+ function baseNth(array, n) {
+ var length = array.length;
+ if (!length) {
+ return;
+ }
+ n += n < 0 ? length : 0;
+ return isIndex(n, length) ? array[n] : undefined;
+ }
+
+ /**
+ * The base implementation of `_.orderBy` without param guards.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+ * @param {string[]} orders The sort orders of `iteratees`.
+ * @returns {Array} Returns the new sorted array.
+ */
+ function baseOrderBy(collection, iteratees, orders) {
+ if (iteratees.length) {
+ iteratees = arrayMap(iteratees, function(iteratee) {
+ if (isArray(iteratee)) {
+ return function(value) {
+ return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
+ }
+ }
+ return iteratee;
+ });
+ } else {
+ iteratees = [identity];
+ }
+
+ var index = -1;
+ iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
+
+ var result = baseMap(collection, function(value, key, collection) {
+ var criteria = arrayMap(iteratees, function(iteratee) {
+ return iteratee(value);
+ });
+ return { 'criteria': criteria, 'index': ++index, 'value': value };
+ });
+
+ return baseSortBy(result, function(object, other) {
+ return compareMultiple(object, other, orders);
+ });
+ }
+
+ /**
+ * The base implementation of `_.pick` without support for individual
+ * property identifiers.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} paths The property paths to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function basePick(object, paths) {
+ return basePickBy(object, paths, function(value, path) {
+ return hasIn(object, path);
+ });
+ }
+
+ /**
+ * The base implementation of `_.pickBy` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} paths The property paths to pick.
+ * @param {Function} predicate The function invoked per property.
+ * @returns {Object} Returns the new object.
+ */
+ function basePickBy(object, paths, predicate) {
+ var index = -1,
+ length = paths.length,
+ result = {};
+
+ while (++index < length) {
+ var path = paths[index],
+ value = baseGet(object, path);
+
+ if (predicate(value, path)) {
+ baseSet(result, castPath(path, object), value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseProperty` which supports deep paths.
+ *
+ * @private
+ * @param {Array|string} path The path of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function basePropertyDeep(path) {
+ return function(object) {
+ return baseGet(object, path);
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAllBy` without support for iteratee
+ * shorthands.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to remove.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns `array`.
+ */
+ function basePullAll(array, values, iteratee, comparator) {
+ var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
+ index = -1,
+ length = values.length,
+ seen = array;
+
+ if (array === values) {
+ values = copyArray(values);
+ }
+ if (iteratee) {
+ seen = arrayMap(array, baseUnary(iteratee));
+ }
+ while (++index < length) {
+ var fromIndex = 0,
+ value = values[index],
+ computed = iteratee ? iteratee(value) : value;
+
+ while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
+ if (seen !== array) {
+ splice.call(seen, fromIndex, 1);
+ }
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * indexes or capturing the removed elements.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns `array`.
+ */
+ function basePullAt(array, indexes) {
+ var length = array ? indexes.length : 0,
+ lastIndex = length - 1;
+
+ while (length--) {
+ var index = indexes[length];
+ if (length == lastIndex || index !== previous) {
+ var previous = index;
+ if (isIndex(index)) {
+ splice.call(array, index, 1);
+ } else {
+ baseUnset(array, index);
+ }
+ }
+ }
+ return array;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for returning
+ * floating-point numbers.
+ *
+ * @private
+ * @param {number} lower The lower bound.
+ * @param {number} upper The upper bound.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(lower, upper) {
+ return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
+ }
+
+ /**
+ * The base implementation of `_.range` and `_.rangeRight` which doesn't
+ * coerce arguments.
+ *
+ * @private
+ * @param {number} start The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} step The value to increment or decrement by.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Array} Returns the range of numbers.
+ */
+ function baseRange(start, end, step, fromRight) {
+ var index = -1,
+ length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (length--) {
+ result[fromRight ? length : ++index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.repeat` which doesn't coerce arguments.
+ *
+ * @private
+ * @param {string} string The string to repeat.
+ * @param {number} n The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ */
+ function baseRepeat(string, n) {
+ var result = '';
+ if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = nativeFloor(n / 2);
+ if (n) {
+ string += string;
+ }
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+ *
+ * @private
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ */
+ function baseRest(func, start) {
+ return setToString(overRest(func, start, identity), func + '');
+ }
+
+ /**
+ * The base implementation of `_.sample`.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to sample.
+ * @returns {*} Returns the random element.
+ */
+ function baseSample(collection) {
+ return arraySample(values(collection));
+ }
+
+ /**
+ * The base implementation of `_.sampleSize` without param guards.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to sample.
+ * @param {number} n The number of elements to sample.
+ * @returns {Array} Returns the random elements.
+ */
+ function baseSampleSize(collection, n) {
+ var array = values(collection);
+ return shuffleSelf(array, baseClamp(n, 0, array.length));
+ }
+
+ /**
+ * The base implementation of `_.set`.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {Array|string} path The path of the property to set.
+ * @param {*} value The value to set.
+ * @param {Function} [customizer] The function to customize path creation.
+ * @returns {Object} Returns `object`.
+ */
+ function baseSet(object, path, value, customizer) {
+ if (!isObject(object)) {
+ return object;
+ }
+ path = castPath(path, object);
+
+ var index = -1,
+ length = path.length,
+ lastIndex = length - 1,
+ nested = object;
+
+ while (nested != null && ++index < length) {
+ var key = toKey(path[index]),
+ newValue = value;
+
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
+ return object;
+ }
+
+ if (index != lastIndex) {
+ var objValue = nested[key];
+ newValue = customizer ? customizer(objValue, key, nested) : undefined;
+ if (newValue === undefined) {
+ newValue = isObject(objValue)
+ ? objValue
+ : (isIndex(path[index + 1]) ? [] : {});
+ }
+ }
+ assignValue(nested, key, newValue);
+ nested = nested[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop shorting.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `setToString` without support for hot loop shorting.
+ *
+ * @private
+ * @param {Function} func The function to modify.
+ * @param {Function} string The `toString` result.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetToString = !defineProperty ? identity : function(func, string) {
+ return defineProperty(func, 'toString', {
+ 'configurable': true,
+ 'enumerable': false,
+ 'value': constant(string),
+ 'writable': true
+ });
+ };
+
+ /**
+ * The base implementation of `_.shuffle`.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ */
+ function baseShuffle(collection) {
+ return shuffleSelf(values(collection));
+ }
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = end > length ? length : end;
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : ((end - start) >>> 0);
+ start >>>= 0;
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
+ * performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest qualified index.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function baseSortedIndex(array, value, retHighest) {
+ var low = 0,
+ high = array == null ? low : array.length;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (computed !== null && !isSymbol(computed) &&
+ (retHighest ? (computed <= value) : (computed < value))) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return baseSortedIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
+ * which invokes `iteratee` for `value` and each element of `array` to compute
+ * their sort ranking. The iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The iteratee invoked per element.
+ * @param {boolean} [retHighest] Specify returning the highest qualified index.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function baseSortedIndexBy(array, value, iteratee, retHighest) {
+ var low = 0,
+ high = array == null ? 0 : array.length;
+ if (high === 0) {
+ return 0;
+ }
+
+ value = iteratee(value);
+ var valIsNaN = value !== value,
+ valIsNull = value === null,
+ valIsSymbol = isSymbol(value),
+ valIsUndefined = value === undefined;
+
+ while (low < high) {
+ var mid = nativeFloor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ othIsDefined = computed !== undefined,
+ othIsNull = computed === null,
+ othIsReflexive = computed === computed,
+ othIsSymbol = isSymbol(computed);
+
+ if (valIsNaN) {
+ var setLow = retHighest || othIsReflexive;
+ } else if (valIsUndefined) {
+ setLow = othIsReflexive && (retHighest || othIsDefined);
+ } else if (valIsNull) {
+ setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
+ } else if (valIsSymbol) {
+ setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
+ } else if (othIsNull || othIsSymbol) {
+ setLow = false;
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
+ * support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ */
+ function baseSortedUniq(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ resIndex = 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value) : value;
+
+ if (!index || !eq(computed, seen)) {
+ var seen = computed;
+ result[resIndex++] = value === 0 ? 0 : value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.toNumber` which doesn't ensure correct
+ * conversions of binary, hexadecimal, or octal string values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ */
+ function baseToNumber(value) {
+ if (typeof value == 'number') {
+ return value;
+ }
+ if (isSymbol(value)) {
+ return NAN;
+ }
+ return +value;
+ }
+
+ /**
+ * The base implementation of `_.toString` which doesn't convert nullish
+ * values to empty strings.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ // Exit early for strings to avoid a performance hit in some environments.
+ if (typeof value == 'string') {
+ return value;
+ }
+ if (isArray(value)) {
+ // Recursively convert values (susceptible to call stack limits).
+ return arrayMap(value, baseToString) + '';
+ }
+ if (isSymbol(value)) {
+ return symbolToString ? symbolToString.call(value) : '';
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ */
+ function baseUniq(array, iteratee, comparator) {
+ var index = -1,
+ includes = arrayIncludes,
+ length = array.length,
+ isCommon = true,
+ result = [],
+ seen = result;
+
+ if (comparator) {
+ isCommon = false;
+ includes = arrayIncludesWith;
+ }
+ else if (length >= LARGE_ARRAY_SIZE) {
+ var set = iteratee ? null : createSet(array);
+ if (set) {
+ return setToArray(set);
+ }
+ isCommon = false;
+ includes = cacheHas;
+ seen = new SetCache;
+ }
+ else {
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value) : value;
+
+ value = (comparator || value !== 0) ? value : 0;
+ if (isCommon && computed === computed) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (!includes(seen, computed, comparator)) {
+ if (seen !== result) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.unset`.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {Array|string} path The property path to unset.
+ * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+ */
+ function baseUnset(object, path) {
+ path = castPath(path, object);
+ object = parent(object, path);
+ return object == null || delete object[toKey(last(path))];
+ }
+
+ /**
+ * The base implementation of `_.update`.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {Array|string} path The path of the property to update.
+ * @param {Function} updater The function to produce the updated value.
+ * @param {Function} [customizer] The function to customize path creation.
+ * @returns {Object} Returns `object`.
+ */
+ function baseUpdate(object, path, updater, customizer) {
+ return baseSet(object, path, updater(baseGet(object, path)), customizer);
+ }
+
+ /**
+ * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
+ * without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to query.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseWhile(array, predicate, isDrop, fromRight) {
+ var length = array.length,
+ index = fromRight ? length : -1;
+
+ while ((fromRight ? index-- : ++index < length) &&
+ predicate(array[index], index, array)) {}
+
+ return isDrop
+ ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
+ : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to perform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ return arrayReduce(actions, function(result, action) {
+ return action.func.apply(action.thisArg, arrayPush([result], action.args));
+ }, result);
+ }
+
+ /**
+ * The base implementation of methods like `_.xor`, without support for
+ * iteratee shorthands, that accepts an array of arrays to inspect.
+ *
+ * @private
+ * @param {Array} arrays The arrays to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of values.
+ */
+ function baseXor(arrays, iteratee, comparator) {
+ var length = arrays.length;
+ if (length < 2) {
+ return length ? baseUniq(arrays[0]) : [];
+ }
+ var index = -1,
+ result = Array(length);
+
+ while (++index < length) {
+ var array = arrays[index],
+ othIndex = -1;
+
+ while (++othIndex < length) {
+ if (othIndex != index) {
+ result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
+ }
+ }
+ }
+ return baseUniq(baseFlatten(result, 1), iteratee, comparator);
+ }
+
+ /**
+ * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
+ *
+ * @private
+ * @param {Array} props The property identifiers.
+ * @param {Array} values The property values.
+ * @param {Function} assignFunc The function to assign values.
+ * @returns {Object} Returns the new object.
+ */
+ function baseZipObject(props, values, assignFunc) {
+ var index = -1,
+ length = props.length,
+ valsLength = values.length,
+ result = {};
+
+ while (++index < length) {
+ var value = index < valsLength ? values[index] : undefined;
+ assignFunc(result, props[index], value);
+ }
+ return result;
+ }
+
+ /**
+ * Casts `value` to an empty array if it's not an array like object.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {Array|Object} Returns the cast array-like object.
+ */
+ function castArrayLikeObject(value) {
+ return isArrayLikeObject(value) ? value : [];
+ }
+
+ /**
+ * Casts `value` to `identity` if it's not a function.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {Function} Returns cast function.
+ */
+ function castFunction(value) {
+ return typeof value == 'function' ? value : identity;
+ }
+
+ /**
+ * Casts `value` to a path array if it's not one.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {Array} Returns the cast property path array.
+ */
+ function castPath(value, object) {
+ if (isArray(value)) {
+ return value;
+ }
+ return isKey(value, object) ? [value] : stringToPath(toString(value));
+ }
+
+ /**
+ * A `baseRest` alias which can be replaced with `identity` by module
+ * replacement plugins.
+ *
+ * @private
+ * @type {Function}
+ * @param {Function} func The function to apply a rest parameter to.
+ * @returns {Function} Returns the new function.
+ */
+ var castRest = baseRest;
+
+ /**
+ * Casts `array` to a slice if it's needed.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {number} start The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the cast slice.
+ */
+ function castSlice(array, start, end) {
+ var length = array.length;
+ end = end === undefined ? length : end;
+ return (!start && end >= length) ? array : baseSlice(array, start, end);
+ }
+
+ /**
+ * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
+ *
+ * @private
+ * @param {number|Object} id The timer id or timeout object of the timer to clear.
+ */
+ var clearTimeout = ctxClearTimeout || function(id) {
+ return root.clearTimeout(id);
+ };
+
+ /**
+ * Creates a clone of `buffer`.
+ *
+ * @private
+ * @param {Buffer} buffer The buffer to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Buffer} Returns the cloned buffer.
+ */
+ function cloneBuffer(buffer, isDeep) {
+ if (isDeep) {
+ return buffer.slice();
+ }
+ var length = buffer.length,
+ result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
+
+ buffer.copy(result);
+ return result;
+ }
+
+ /**
+ * Creates a clone of `arrayBuffer`.
+ *
+ * @private
+ * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function cloneArrayBuffer(arrayBuffer) {
+ var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
+ new Uint8Array(result).set(new Uint8Array(arrayBuffer));
+ return result;
+ }
+
+ /**
+ * Creates a clone of `dataView`.
+ *
+ * @private
+ * @param {Object} dataView The data view to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned data view.
+ */
+ function cloneDataView(dataView, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+ return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+ }
+
+ /**
+ * Creates a clone of `regexp`.
+ *
+ * @private
+ * @param {Object} regexp The regexp to clone.
+ * @returns {Object} Returns the cloned regexp.
+ */
+ function cloneRegExp(regexp) {
+ var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+ result.lastIndex = regexp.lastIndex;
+ return result;
+ }
+
+ /**
+ * Creates a clone of the `symbol` object.
+ *
+ * @private
+ * @param {Object} symbol The symbol object to clone.
+ * @returns {Object} Returns the cloned symbol object.
+ */
+ function cloneSymbol(symbol) {
+ return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+ }
+
+ /**
+ * Creates a clone of `typedArray`.
+ *
+ * @private
+ * @param {Object} typedArray The typed array to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned typed array.
+ */
+ function cloneTypedArray(typedArray, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
+ return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
+ }
+
+ /**
+ * Compares values to sort them in ascending order.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function compareAscending(value, other) {
+ if (value !== other) {
+ var valIsDefined = value !== undefined,
+ valIsNull = value === null,
+ valIsReflexive = value === value,
+ valIsSymbol = isSymbol(value);
+
+ var othIsDefined = other !== undefined,
+ othIsNull = other === null,
+ othIsReflexive = other === other,
+ othIsSymbol = isSymbol(other);
+
+ if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
+ (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
+ (valIsNull && othIsDefined && othIsReflexive) ||
+ (!valIsDefined && othIsReflexive) ||
+ !valIsReflexive) {
+ return 1;
+ }
+ if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
+ (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
+ (othIsNull && valIsDefined && valIsReflexive) ||
+ (!othIsDefined && valIsReflexive) ||
+ !othIsReflexive) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Used by `_.orderBy` to compare multiple properties of a value to another
+ * and stable sort them.
+ *
+ * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
+ * specify an order of "desc" for descending or "asc" for ascending sort order
+ * of corresponding values.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {boolean[]|string[]} orders The order to sort by for each property.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultiple(object, other, orders) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length,
+ ordersLength = orders.length;
+
+ while (++index < length) {
+ var result = compareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ if (index >= ordersLength) {
+ return result;
+ }
+ var order = orders[index];
+ return result * (order == 'desc' ? -1 : 1);
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value for
+ // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
+ // for more details.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
+ return object.index - other.index;
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @params {boolean} [isCurried] Specify composing for a curried function.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders, isCurried) {
+ var argsIndex = -1,
+ argsLength = args.length,
+ holdersLength = holders.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ rangeLength = nativeMax(argsLength - holdersLength, 0),
+ result = Array(leftLength + rangeLength),
+ isUncurried = !isCurried;
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ if (isUncurried || argsIndex < argsLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ }
+ while (rangeLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @params {boolean} [isCurried] Specify composing for a curried function.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders, isCurried) {
+ var argsIndex = -1,
+ argsLength = args.length,
+ holdersIndex = -1,
+ holdersLength = holders.length,
+ rightIndex = -1,
+ rightLength = partials.length,
+ rangeLength = nativeMax(argsLength - holdersLength, 0),
+ result = Array(rangeLength + rightLength),
+ isUncurried = !isCurried;
+
+ while (++argsIndex < rangeLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var offset = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[offset + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ if (isUncurried || argsIndex < argsLength) {
+ result[offset + holders[holdersIndex]] = args[argsIndex++];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function copyArray(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property identifiers to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Function} [customizer] The function to customize copied values.
+ * @returns {Object} Returns `object`.
+ */
+ function copyObject(source, props, object, customizer) {
+ var isNew = !object;
+ object || (object = {});
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+
+ var newValue = customizer
+ ? customizer(object[key], source[key], key, object, source)
+ : undefined;
+
+ if (newValue === undefined) {
+ newValue = source[key];
+ }
+ if (isNew) {
+ baseAssignValue(object, key, newValue);
+ } else {
+ assignValue(object, key, newValue);
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Copies own symbols of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+ function copySymbols(source, object) {
+ return copyObject(source, getSymbols(source), object);
+ }
+
+ /**
+ * Copies own and inherited symbols of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+ function copySymbolsIn(source, object) {
+ return copyObject(source, getSymbolsIn(source), object);
+ }
+
+ /**
+ * Creates a function like `_.groupBy`.
+ *
+ * @private
+ * @param {Function} setter The function to set accumulator values.
+ * @param {Function} [initializer] The accumulator object initializer.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee) {
+ var func = isArray(collection) ? arrayAggregator : baseAggregator,
+ accumulator = initializer ? initializer() : {};
+
+ return func(collection, setter, getIteratee(iteratee, 2), accumulator);
+ };
+ }
+
+ /**
+ * Creates a function like `_.assign`.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return baseRest(function(object, sources) {
+ var index = -1,
+ length = sources.length,
+ customizer = length > 1 ? sources[length - 1] : undefined,
+ guard = length > 2 ? sources[2] : undefined;
+
+ customizer = (assigner.length > 3 && typeof customizer == 'function')
+ ? (length--, customizer)
+ : undefined;
+
+ if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+ customizer = length < 3 ? undefined : customizer;
+ length = 1;
+ }
+ object = Object(object);
+ while (++index < length) {
+ var source = sources[index];
+ if (source) {
+ assigner(object, source, index, customizer);
+ }
+ }
+ return object;
+ });
+ }
+
+ /**
+ * Creates a `baseEach` or `baseEachRight` function.
+ *
+ * @private
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+ function createBaseEach(eachFunc, fromRight) {
+ return function(collection, iteratee) {
+ if (collection == null) {
+ return collection;
+ }
+ if (!isArrayLike(collection)) {
+ return eachFunc(collection, iteratee);
+ }
+ var length = collection.length,
+ index = fromRight ? length : -1,
+ iterable = Object(collection);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ };
+ }
+
+ /**
+ * Creates a base function for methods like `_.forIn` and `_.forOwn`.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+ function createBaseFor(fromRight) {
+ return function(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = Object(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (length--) {
+ var key = props[fromRight ? length : ++index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` to invoke it with the optional `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createBind(func, bitmask, thisArg) {
+ var isBind = bitmask & WRAP_BIND_FLAG,
+ Ctor = createCtor(func);
+
+ function wrapper() {
+ var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+ return fn.apply(isBind ? thisArg : this, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function like `_.lowerFirst`.
+ *
+ * @private
+ * @param {string} methodName The name of the `String` case method to use.
+ * @returns {Function} Returns the new case function.
+ */
+ function createCaseFirst(methodName) {
+ return function(string) {
+ string = toString(string);
+
+ var strSymbols = hasUnicode(string)
+ ? stringToArray(string)
+ : undefined;
+
+ var chr = strSymbols
+ ? strSymbols[0]
+ : string.charAt(0);
+
+ var trailing = strSymbols
+ ? castSlice(strSymbols, 1).join('')
+ : string.slice(1);
+
+ return chr[methodName]() + trailing;
+ };
+ }
+
+ /**
+ * Creates a function like `_.camelCase`.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtor(Ctor) {
+ return function() {
+ // Use a `switch` statement to work with class constructors. See
+ // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
+ // for more details.
+ var args = arguments;
+ switch (args.length) {
+ case 0: return new Ctor;
+ case 1: return new Ctor(args[0]);
+ case 2: return new Ctor(args[0], args[1]);
+ case 3: return new Ctor(args[0], args[1], args[2]);
+ case 4: return new Ctor(args[0], args[1], args[2], args[3]);
+ case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
+ case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
+ case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+ }
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, args);
+
+ // Mimic the constructor's `return` behavior.
+ // See https://es5.github.io/#x13.2.2 for more details.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` to enable currying.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @param {number} arity The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCurry(func, bitmask, arity) {
+ var Ctor = createCtor(func);
+
+ function wrapper() {
+ var length = arguments.length,
+ args = Array(length),
+ index = length,
+ placeholder = getHolder(wrapper);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
+ ? []
+ : replaceHolders(args, placeholder);
+
+ length -= holders.length;
+ if (length < arity) {
+ return createRecurry(
+ func, bitmask, createHybrid, wrapper.placeholder, undefined,
+ args, holders, undefined, undefined, arity - length);
+ }
+ var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+ return apply(fn, this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `_.find` or `_.findLast` function.
+ *
+ * @private
+ * @param {Function} findIndexFunc The function to find the collection index.
+ * @returns {Function} Returns the new find function.
+ */
+ function createFind(findIndexFunc) {
+ return function(collection, predicate, fromIndex) {
+ var iterable = Object(collection);
+ if (!isArrayLike(collection)) {
+ var iteratee = getIteratee(predicate, 3);
+ collection = keys(collection);
+ predicate = function(key) { return iteratee(iterable[key], key, iterable); };
+ }
+ var index = findIndexFunc(collection, predicate, fromIndex);
+ return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
+ };
+ }
+
+ /**
+ * Creates a `_.flow` or `_.flowRight` function.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new flow function.
+ */
+ function createFlow(fromRight) {
+ return flatRest(function(funcs) {
+ var length = funcs.length,
+ index = length,
+ prereq = LodashWrapper.prototype.thru;
+
+ if (fromRight) {
+ funcs.reverse();
+ }
+ while (index--) {
+ var func = funcs[index];
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
+ var wrapper = new LodashWrapper([], true);
+ }
+ }
+ index = wrapper ? index : length;
+ while (++index < length) {
+ func = funcs[index];
+
+ var funcName = getFuncName(func),
+ data = funcName == 'wrapper' ? getData(func) : undefined;
+
+ if (data && isLaziable(data[0]) &&
+ data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
+ !data[4].length && data[9] == 1
+ ) {
+ wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
+ } else {
+ wrapper = (func.length == 1 && isLaziable(func))
+ ? wrapper[funcName]()
+ : wrapper.thru(func);
+ }
+ }
+ return function() {
+ var args = arguments,
+ value = args[0];
+
+ if (wrapper && args.length == 1 && isArray(value)) {
+ return wrapper.plant(value).value();
+ }
+ var index = 0,
+ result = length ? funcs[index].apply(this, args) : value;
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ });
+ }
+
+ /**
+ * Creates a function that wraps `func` to invoke it with optional `this`
+ * binding of `thisArg`, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to wrap.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to
+ * the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided
+ * to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & WRAP_ARY_FLAG,
+ isBind = bitmask & WRAP_BIND_FLAG,
+ isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
+ isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
+ isFlip = bitmask & WRAP_FLIP_FLAG,
+ Ctor = isBindKey ? undefined : createCtor(func);
+
+ function wrapper() {
+ var length = arguments.length,
+ args = Array(length),
+ index = length;
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (isCurried) {
+ var placeholder = getHolder(wrapper),
+ holdersCount = countHolders(args, placeholder);
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders, isCurried);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
+ }
+ length -= holdersCount;
+ if (isCurried && length < arity) {
+ var newHolders = replaceHolders(args, placeholder);
+ return createRecurry(
+ func, bitmask, createHybrid, wrapper.placeholder, thisArg,
+ args, newHolders, argPos, ary, arity - length
+ );
+ }
+ var thisBinding = isBind ? thisArg : this,
+ fn = isBindKey ? thisBinding[func] : func;
+
+ length = args.length;
+ if (argPos) {
+ args = reorder(args, argPos);
+ } else if (isFlip && length > 1) {
+ args.reverse();
+ }
+ if (isAry && ary < length) {
+ args.length = ary;
+ }
+ if (this && this !== root && this instanceof wrapper) {
+ fn = Ctor || createCtor(fn);
+ }
+ return fn.apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function like `_.invertBy`.
+ *
+ * @private
+ * @param {Function} setter The function to set accumulator values.
+ * @param {Function} toIteratee The function to resolve iteratees.
+ * @returns {Function} Returns the new inverter function.
+ */
+ function createInverter(setter, toIteratee) {
+ return function(object, iteratee) {
+ return baseInverter(object, setter, toIteratee(iteratee), {});
+ };
+ }
+
+ /**
+ * Creates a function that performs a mathematical operation on two values.
+ *
+ * @private
+ * @param {Function} operator The function to perform the operation.
+ * @param {number} [defaultValue] The value used for `undefined` arguments.
+ * @returns {Function} Returns the new mathematical operation function.
+ */
+ function createMathOperation(operator, defaultValue) {
+ return function(value, other) {
+ var result;
+ if (value === undefined && other === undefined) {
+ return defaultValue;
+ }
+ if (value !== undefined) {
+ result = value;
+ }
+ if (other !== undefined) {
+ if (result === undefined) {
+ return other;
+ }
+ if (typeof value == 'string' || typeof other == 'string') {
+ value = baseToString(value);
+ other = baseToString(other);
+ } else {
+ value = baseToNumber(value);
+ other = baseToNumber(other);
+ }
+ result = operator(value, other);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function like `_.over`.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to iterate over iteratees.
+ * @returns {Function} Returns the new over function.
+ */
+ function createOver(arrayFunc) {
+ return flatRest(function(iteratees) {
+ iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
+ return baseRest(function(args) {
+ var thisArg = this;
+ return arrayFunc(iteratees, function(iteratee) {
+ return apply(iteratee, thisArg, args);
+ });
+ });
+ });
+ }
+
+ /**
+ * Creates the padding for `string` based on `length`. The `chars` string
+ * is truncated if the number of characters exceeds `length`.
+ *
+ * @private
+ * @param {number} length The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padding for `string`.
+ */
+ function createPadding(length, chars) {
+ chars = chars === undefined ? ' ' : baseToString(chars);
+
+ var charsLength = chars.length;
+ if (charsLength < 2) {
+ return charsLength ? baseRepeat(chars, length) : chars;
+ }
+ var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
+ return hasUnicode(chars)
+ ? castSlice(stringToArray(result), 0, length).join('')
+ : result.slice(0, length);
+ }
+
+ /**
+ * Creates a function that wraps `func` to invoke it with the `this` binding
+ * of `thisArg` and `partials` prepended to the arguments it receives.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to
+ * the new function.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createPartial(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & WRAP_BIND_FLAG,
+ Ctor = createCtor(func);
+
+ function wrapper() {
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(leftLength + argsLength),
+ fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return apply(fn, isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `_.range` or `_.rangeRight` function.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new range function.
+ */
+ function createRange(fromRight) {
+ return function(start, end, step) {
+ if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
+ end = step = undefined;
+ }
+ // Ensure the sign of `-0` is preserved.
+ start = toFinite(start);
+ if (end === undefined) {
+ end = start;
+ start = 0;
+ } else {
+ end = toFinite(end);
+ }
+ step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
+ return baseRange(start, end, step, fromRight);
+ };
+ }
+
+ /**
+ * Creates a function that performs a relational operation on two values.
+ *
+ * @private
+ * @param {Function} operator The function to perform the operation.
+ * @returns {Function} Returns the new relational operation function.
+ */
+ function createRelationalOperation(operator) {
+ return function(value, other) {
+ if (!(typeof value == 'string' && typeof other == 'string')) {
+ value = toNumber(value);
+ other = toNumber(other);
+ }
+ return operator(value, other);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` to continue currying.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @param {Function} wrapFunc The function to create the `func` wrapper.
+ * @param {*} placeholder The placeholder value.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to
+ * the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
+ var isCurry = bitmask & WRAP_CURRY_FLAG,
+ newHolders = isCurry ? holders : undefined,
+ newHoldersRight = isCurry ? undefined : holders,
+ newPartials = isCurry ? partials : undefined,
+ newPartialsRight = isCurry ? undefined : partials;
+
+ bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
+
+ if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
+ bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
+ }
+ var newData = [
+ func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
+ newHoldersRight, argPos, ary, arity
+ ];
+
+ var result = wrapFunc.apply(undefined, newData);
+ if (isLaziable(func)) {
+ setData(result, newData);
+ }
+ result.placeholder = placeholder;
+ return setWrapToString(result, func, bitmask);
+ }
+
+ /**
+ * Creates a function like `_.round`.
+ *
+ * @private
+ * @param {string} methodName The name of the `Math` method to use when rounding.
+ * @returns {Function} Returns the new round function.
+ */
+ function createRound(methodName) {
+ var func = Math[methodName];
+ return function(number, precision) {
+ number = toNumber(number);
+ precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
+ if (precision && nativeIsFinite(number)) {
+ // Shift with exponential notation to avoid floating-point issues.
+ // See [MDN](https://mdn.io/round#Examples) for more details.
+ var pair = (toString(number) + 'e').split('e'),
+ value = func(pair[0] + 'e' + (+pair[1] + precision));
+
+ pair = (toString(value) + 'e').split('e');
+ return +(pair[0] + 'e' + (+pair[1] - precision));
+ }
+ return func(number);
+ };
+ }
+
+ /**
+ * Creates a set object of `values`.
+ *
+ * @private
+ * @param {Array} values The values to add to the set.
+ * @returns {Object} Returns the new set.
+ */
+ var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
+ return new Set(values);
+ };
+
+ /**
+ * Creates a `_.toPairs` or `_.toPairsIn` function.
+ *
+ * @private
+ * @param {Function} keysFunc The function to get the keys of a given object.
+ * @returns {Function} Returns the new pairs function.
+ */
+ function createToPairs(keysFunc) {
+ return function(object) {
+ var tag = getTag(object);
+ if (tag == mapTag) {
+ return mapToArray(object);
+ }
+ if (tag == setTag) {
+ return setToPairs(object);
+ }
+ return baseToPairs(object, keysFunc(object));
+ };
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to wrap.
+ * @param {number} bitmask The bitmask flags.
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * 512 - `_.flip`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
+ if (!isBindKey && typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
+ partials = holders = undefined;
+ }
+ ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
+ arity = arity === undefined ? arity : toInteger(arity);
+ length -= holders ? holders.length : 0;
+
+ if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = undefined;
+ }
+ var data = isBindKey ? undefined : getData(func);
+
+ var newData = [
+ func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
+ argPos, ary, arity
+ ];
+
+ if (data) {
+ mergeData(newData, data);
+ }
+ func = newData[0];
+ bitmask = newData[1];
+ thisArg = newData[2];
+ partials = newData[3];
+ holders = newData[4];
+ arity = newData[9] = newData[9] === undefined
+ ? (isBindKey ? 0 : func.length)
+ : nativeMax(newData[9] - length, 0);
+
+ if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
+ bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
+ }
+ if (!bitmask || bitmask == WRAP_BIND_FLAG) {
+ var result = createBind(func, bitmask, thisArg);
+ } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
+ result = createCurry(func, bitmask, arity);
+ } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
+ result = createPartial(func, bitmask, thisArg, partials);
+ } else {
+ result = createHybrid.apply(undefined, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setWrapToString(setter(result, newData), func, bitmask);
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
+ * of source objects to the destination object for all destination properties
+ * that resolve to `undefined`.
+ *
+ * @private
+ * @param {*} objValue The destination value.
+ * @param {*} srcValue The source value.
+ * @param {string} key The key of the property to assign.
+ * @param {Object} object The parent object of `objValue`.
+ * @returns {*} Returns the value to assign.
+ */
+ function customDefaultsAssignIn(objValue, srcValue, key, object) {
+ if (objValue === undefined ||
+ (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
+ return srcValue;
+ }
+ return objValue;
+ }
+
+ /**
+ * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
+ * objects into destination objects that are passed thru.
+ *
+ * @private
+ * @param {*} objValue The destination value.
+ * @param {*} srcValue The source value.
+ * @param {string} key The key of the property to merge.
+ * @param {Object} object The parent object of `objValue`.
+ * @param {Object} source The parent object of `srcValue`.
+ * @param {Object} [stack] Tracks traversed source values and their merged
+ * counterparts.
+ * @returns {*} Returns the value to assign.
+ */
+ function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
+ if (isObject(objValue) && isObject(srcValue)) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ stack.set(srcValue, objValue);
+ baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
+ stack['delete'](srcValue);
+ }
+ return objValue;
+ }
+
+ /**
+ * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
+ * objects.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @param {string} key The key of the property to inspect.
+ * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
+ */
+ function customOmitClone(value) {
+ return isPlainObject(value) ? undefined : value;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Object} stack Tracks traversed `array` and `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
+ var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
+ arrLength = array.length,
+ othLength = other.length;
+
+ if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
+ return false;
+ }
+ // Check that cyclic values are equal.
+ var arrStacked = stack.get(array);
+ var othStacked = stack.get(other);
+ if (arrStacked && othStacked) {
+ return arrStacked == other && othStacked == array;
+ }
+ var index = -1,
+ result = true,
+ seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
+
+ stack.set(array, other);
+ stack.set(other, array);
+
+ // Ignore non-index properties.
+ while (++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, arrValue, index, other, array, stack)
+ : customizer(arrValue, othValue, index, array, other, stack);
+ }
+ if (compared !== undefined) {
+ if (compared) {
+ continue;
+ }
+ result = false;
+ break;
+ }
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (seen) {
+ if (!arraySome(other, function(othValue, othIndex) {
+ if (!cacheHas(seen, othIndex) &&
+ (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
+ return seen.push(othIndex);
+ }
+ })) {
+ result = false;
+ break;
+ }
+ } else if (!(
+ arrValue === othValue ||
+ equalFunc(arrValue, othValue, bitmask, customizer, stack)
+ )) {
+ result = false;
+ break;
+ }
+ }
+ stack['delete'](array);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
+ switch (tag) {
+ case dataViewTag:
+ if ((object.byteLength != other.byteLength) ||
+ (object.byteOffset != other.byteOffset)) {
+ return false;
+ }
+ object = object.buffer;
+ other = other.buffer;
+
+ case arrayBufferTag:
+ if ((object.byteLength != other.byteLength) ||
+ !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
+ return false;
+ }
+ return true;
+
+ case boolTag:
+ case dateTag:
+ case numberTag:
+ // Coerce booleans to `1` or `0` and dates to milliseconds.
+ // Invalid dates are coerced to `NaN`.
+ return eq(+object, +other);
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings and treat strings, primitives and objects,
+ // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
+ // for more details.
+ return object == (other + '');
+
+ case mapTag:
+ var convert = mapToArray;
+
+ case setTag:
+ var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
+ convert || (convert = setToArray);
+
+ if (object.size != other.size && !isPartial) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(object);
+ if (stacked) {
+ return stacked == other;
+ }
+ bitmask |= COMPARE_UNORDERED_FLAG;
+
+ // Recursively compare objects (susceptible to call stack limits).
+ stack.set(object, other);
+ var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
+ stack['delete'](object);
+ return result;
+
+ case symbolTag:
+ if (symbolValueOf) {
+ return symbolValueOf.call(object) == symbolValueOf.call(other);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
+ var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
+ objProps = getAllKeys(object),
+ objLength = objProps.length,
+ othProps = getAllKeys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isPartial) {
+ return false;
+ }
+ var index = objLength;
+ while (index--) {
+ var key = objProps[index];
+ if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
+ return false;
+ }
+ }
+ // Check that cyclic values are equal.
+ var objStacked = stack.get(object);
+ var othStacked = stack.get(other);
+ if (objStacked && othStacked) {
+ return objStacked == other && othStacked == object;
+ }
+ var result = true;
+ stack.set(object, other);
+ stack.set(other, object);
+
+ var skipCtor = isPartial;
+ while (++index < objLength) {
+ key = objProps[index];
+ var objValue = object[key],
+ othValue = other[key];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, objValue, key, other, object, stack)
+ : customizer(objValue, othValue, key, object, other, stack);
+ }
+ // Recursively compare objects (susceptible to call stack limits).
+ if (!(compared === undefined
+ ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
+ : compared
+ )) {
+ result = false;
+ break;
+ }
+ skipCtor || (skipCtor = key == 'constructor');
+ }
+ if (result && !skipCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor &&
+ ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
+ typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ result = false;
+ }
+ }
+ stack['delete'](object);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseRest` which flattens the rest array.
+ *
+ * @private
+ * @param {Function} func The function to apply a rest parameter to.
+ * @returns {Function} Returns the new function.
+ */
+ function flatRest(func) {
+ return setToString(overRest(func, undefined, flatten), func + '');
+ }
+
+ /**
+ * Creates an array of own enumerable property names and symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function getAllKeys(object) {
+ return baseGetAllKeys(object, keys, getSymbols);
+ }
+
+ /**
+ * Creates an array of own and inherited enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function getAllKeysIn(object) {
+ return baseGetAllKeys(object, keysIn, getSymbolsIn);
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the name of `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {string} Returns the function name.
+ */
+ function getFuncName(func) {
+ var result = (func.name + ''),
+ array = realNames[result],
+ length = hasOwnProperty.call(realNames, result) ? array.length : 0;
+
+ while (length--) {
+ var data = array[length],
+ otherFunc = data.func;
+ if (otherFunc == null || otherFunc == func) {
+ return data.name;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the argument placeholder value for `func`.
+ *
+ * @private
+ * @param {Function} func The function to inspect.
+ * @returns {*} Returns the placeholder value.
+ */
+ function getHolder(func) {
+ var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
+ return object.placeholder;
+ }
+
+ /**
+ * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
+ * this function returns the custom method, otherwise it returns `baseIteratee`.
+ * If arguments are provided, the chosen function is invoked with them and
+ * its result is returned.
+ *
+ * @private
+ * @param {*} [value] The value to convert to an iteratee.
+ * @param {number} [arity] The arity of the created iteratee.
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getIteratee() {
+ var result = lodash.iteratee || iteratee;
+ result = result === iteratee ? baseIteratee : result;
+ return arguments.length ? result(arguments[0], arguments[1]) : result;
+ }
+
+ /**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+ function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+ }
+
+ /**
+ * Gets the property names, values, and compare flags of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the match data of `object`.
+ */
+ function getMatchData(object) {
+ var result = keys(object),
+ length = result.length;
+
+ while (length--) {
+ var key = result[length],
+ value = object[key];
+
+ result[length] = [key, value, isStrictComparable(value)];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+ }
+
+ /**
+ * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the raw `toStringTag`.
+ */
+ function getRawTag(value) {
+ var isOwn = hasOwnProperty.call(value, symToStringTag),
+ tag = value[symToStringTag];
+
+ try {
+ value[symToStringTag] = undefined;
+ var unmasked = true;
+ } catch (e) {}
+
+ var result = nativeObjectToString.call(value);
+ if (unmasked) {
+ if (isOwn) {
+ value[symToStringTag] = tag;
+ } else {
+ delete value[symToStringTag];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+ var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
+ if (object == null) {
+ return [];
+ }
+ object = Object(object);
+ return arrayFilter(nativeGetSymbols(object), function(symbol) {
+ return propertyIsEnumerable.call(object, symbol);
+ });
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+ var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
+ var result = [];
+ while (object) {
+ arrayPush(result, getSymbols(object));
+ object = getPrototype(object);
+ }
+ return result;
+ };
+
+ /**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ var getTag = baseGetTag;
+
+ // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
+ if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+ (Map && getTag(new Map) != mapTag) ||
+ (Promise && getTag(Promise.resolve()) != promiseTag) ||
+ (Set && getTag(new Set) != setTag) ||
+ (WeakMap && getTag(new WeakMap) != weakMapTag)) {
+ getTag = function(value) {
+ var result = baseGetTag(value),
+ Ctor = result == objectTag ? value.constructor : undefined,
+ ctorString = Ctor ? toSource(Ctor) : '';
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag;
+ case mapCtorString: return mapTag;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag;
+ case weakMapCtorString: return weakMapTag;
+ }
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} transforms The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms.length;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Extracts wrapper details from the `source` body comment.
+ *
+ * @private
+ * @param {string} source The source to inspect.
+ * @returns {Array} Returns the wrapper details.
+ */
+ function getWrapDetails(source) {
+ var match = source.match(reWrapDetails);
+ return match ? match[1].split(reSplitDetails) : [];
+ }
+
+ /**
+ * Checks if `path` exists on `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @param {Function} hasFunc The function to check properties.
+ * @returns {boolean} Returns `true` if `path` exists, else `false`.
+ */
+ function hasPath(object, path, hasFunc) {
+ path = castPath(path, object);
+
+ var index = -1,
+ length = path.length,
+ result = false;
+
+ while (++index < length) {
+ var key = toKey(path[index]);
+ if (!(result = object != null && hasFunc(object, key))) {
+ break;
+ }
+ object = object[key];
+ }
+ if (result || ++index != length) {
+ return result;
+ }
+ length = object == null ? 0 : object.length;
+ return !!length && isLength(length) && isIndex(key, length) &&
+ (isArray(object) || isArguments(object));
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ return (typeof object.constructor == 'function' && !isPrototype(object))
+ ? baseCreate(getPrototype(object))
+ : {};
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return cloneArrayBuffer(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case dataViewTag:
+ return cloneDataView(object, isDeep);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ return cloneTypedArray(object, isDeep);
+
+ case mapTag:
+ return new Ctor;
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ return cloneRegExp(object);
+
+ case setTag:
+ return new Ctor;
+
+ case symbolTag:
+ return cloneSymbol(object);
+ }
+ }
+
+ /**
+ * Inserts wrapper `details` in a comment at the top of the `source` body.
+ *
+ * @private
+ * @param {string} source The source to modify.
+ * @returns {Array} details The details to insert.
+ * @returns {string} Returns the modified source.
+ */
+ function insertWrapDetails(source, details) {
+ var length = details.length;
+ if (!length) {
+ return source;
+ }
+ var lastIndex = length - 1;
+ details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
+ details = details.join(length > 2 ? ', ' : ' ');
+ return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
+ }
+
+ /**
+ * Checks if `value` is a flattenable `arguments` object or array.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
+ */
+ function isFlattenable(value) {
+ return isArray(value) || isArguments(value) ||
+ !!(spreadableSymbol && value && value[spreadableSymbol]);
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ var type = typeof value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+
+ return !!length &&
+ (type == 'number' ||
+ (type != 'symbol' && reIsUint.test(value))) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if the given arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+ * else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number'
+ ? (isArrayLike(object) && isIndex(index, object.length))
+ : (type == 'string' && index in object)
+ ) {
+ return eq(object[index], value);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if `value` is a property name and not a property path.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+ */
+ function isKey(value, object) {
+ if (isArray(value)) {
+ return false;
+ }
+ var type = typeof value;
+ if (type == 'number' || type == 'symbol' || type == 'boolean' ||
+ value == null || isSymbol(value)) {
+ return true;
+ }
+ return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
+ (object != null && value in Object(object));
+ }
+
+ /**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+ function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+ }
+
+ /**
+ * Checks if `func` has a lazy counterpart.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
+ * else `false`.
+ */
+ function isLaziable(func) {
+ var funcName = getFuncName(func),
+ other = lodash[funcName];
+
+ if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
+ return false;
+ }
+ if (func === other) {
+ return true;
+ }
+ var data = getData(other);
+ return !!data && func === data[0];
+ }
+
+ /**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+ function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+ }
+
+ /**
+ * Checks if `func` is capable of being masked.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
+ */
+ var isMaskable = coreJsData ? isFunction : stubFalse;
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && !isObject(value);
+ }
+
+ /**
+ * A specialized version of `matchesProperty` for source values suitable
+ * for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @param {*} srcValue The value to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function matchesStrictComparable(key, srcValue) {
+ return function(object) {
+ if (object == null) {
+ return false;
+ }
+ return object[key] === srcValue &&
+ (srcValue !== undefined || (key in Object(object)));
+ };
+ }
+
+ /**
+ * A specialized version of `_.memoize` which clears the memoized function's
+ * cache when it exceeds `MAX_MEMOIZE_SIZE`.
+ *
+ * @private
+ * @param {Function} func The function to have its output memoized.
+ * @returns {Function} Returns the new memoized function.
+ */
+ function memoizeCapped(func) {
+ var result = memoize(func, function(key) {
+ if (cache.size === MAX_MEMOIZE_SIZE) {
+ cache.clear();
+ }
+ return key;
+ });
+
+ var cache = result.cache;
+ return result;
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers used to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and
+ * `_.rearg` modify function arguments, making the order in which they are
+ * executed important, preventing the merging of metadata. However, we make
+ * an exception for a safe combined case where curried functions have `_.ary`
+ * and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask,
+ isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
+
+ var isCombo =
+ ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
+ ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
+ ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & WRAP_BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : value;
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = value;
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & WRAP_ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * This function is like
+ * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * except that it includes inherited enumerable properties.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function nativeKeysIn(object) {
+ var result = [];
+ if (object != null) {
+ for (var key in Object(object)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to a string using `Object.prototype.toString`.
+ *
+ * @private
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ */
+ function objectToString(value) {
+ return nativeObjectToString.call(value);
+ }
+
+ /**
+ * A specialized version of `baseRest` which transforms the rest array.
+ *
+ * @private
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @param {Function} transform The rest array transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overRest(func, start, transform) {
+ start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
+ return function() {
+ var args = arguments,
+ index = -1,
+ length = nativeMax(args.length - start, 0),
+ array = Array(length);
+
+ while (++index < length) {
+ array[index] = args[start + index];
+ }
+ index = -1;
+ var otherArgs = Array(start + 1);
+ while (++index < start) {
+ otherArgs[index] = args[index];
+ }
+ otherArgs[start] = transform(array);
+ return apply(func, this, otherArgs);
+ };
+ }
+
+ /**
+ * Gets the parent value at `path` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} path The path to get the parent value of.
+ * @returns {*} Returns the parent value.
+ */
+ function parent(object, path) {
+ return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = copyArray(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function safeGet(object, key) {
+ if (key === 'constructor' && typeof object[key] === 'function') {
+ return;
+ }
+
+ if (key == '__proto__') {
+ return;
+ }
+
+ return object[key];
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity
+ * function to avoid garbage collection pauses in V8. See
+ * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
+ * for more details.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = shortOut(baseSetData);
+
+ /**
+ * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @returns {number|Object} Returns the timer id or timeout object.
+ */
+ var setTimeout = ctxSetTimeout || function(func, wait) {
+ return root.setTimeout(func, wait);
+ };
+
+ /**
+ * Sets the `toString` method of `func` to return `string`.
+ *
+ * @private
+ * @param {Function} func The function to modify.
+ * @param {Function} string The `toString` result.
+ * @returns {Function} Returns `func`.
+ */
+ var setToString = shortOut(baseSetToString);
+
+ /**
+ * Sets the `toString` method of `wrapper` to mimic the source of `reference`
+ * with wrapper details in a comment at the top of the source body.
+ *
+ * @private
+ * @param {Function} wrapper The function to modify.
+ * @param {Function} reference The reference function.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @returns {Function} Returns `wrapper`.
+ */
+ function setWrapToString(wrapper, reference, bitmask) {
+ var source = (reference + '');
+ return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
+ }
+
+ /**
+ * Creates a function that'll short out and invoke `identity` instead
+ * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
+ * milliseconds.
+ *
+ * @private
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new shortable function.
+ */
+ function shortOut(func) {
+ var count = 0,
+ lastCalled = 0;
+
+ return function() {
+ var stamp = nativeNow(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return arguments[0];
+ }
+ } else {
+ count = 0;
+ }
+ return func.apply(undefined, arguments);
+ };
+ }
+
+ /**
+ * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
+ *
+ * @private
+ * @param {Array} array The array to shuffle.
+ * @param {number} [size=array.length] The size of `array`.
+ * @returns {Array} Returns `array`.
+ */
+ function shuffleSelf(array, size) {
+ var index = -1,
+ length = array.length,
+ lastIndex = length - 1;
+
+ size = size === undefined ? length : size;
+ while (++index < size) {
+ var rand = baseRandom(index, lastIndex),
+ value = array[rand];
+
+ array[rand] = array[index];
+ array[index] = value;
+ }
+ array.length = size;
+ return array;
+ }
+
+ /**
+ * Converts `string` to a property path array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the property path array.
+ */
+ var stringToPath = memoizeCapped(function(string) {
+ var result = [];
+ if (string.charCodeAt(0) === 46 /* . */) {
+ result.push('');
+ }
+ string.replace(rePropName, function(match, number, quote, subString) {
+ result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
+ });
+ return result;
+ });
+
+ /**
+ * Converts `value` to a string key if it's not a string or symbol.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {string|symbol} Returns the key.
+ */
+ function toKey(value) {
+ if (typeof value == 'string' || isSymbol(value)) {
+ return value;
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to convert.
+ * @returns {string} Returns the source code.
+ */
+ function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+ }
+
+ /**
+ * Updates wrapper `details` based on `bitmask` flags.
+ *
+ * @private
+ * @returns {Array} details The details to modify.
+ * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+ * @returns {Array} Returns `details`.
+ */
+ function updateWrapDetails(details, bitmask) {
+ arrayEach(wrapFlags, function(pair) {
+ var value = '_.' + pair[0];
+ if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
+ details.push(value);
+ }
+ });
+ return details.sort();
+ }
+
+ /**
+ * Creates a clone of `wrapper`.
+ *
+ * @private
+ * @param {Object} wrapper The wrapper to clone.
+ * @returns {Object} Returns the cloned wrapper.
+ */
+ function wrapperClone(wrapper) {
+ if (wrapper instanceof LazyWrapper) {
+ return wrapper.clone();
+ }
+ var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
+ result.__actions__ = copyArray(wrapper.__actions__);
+ result.__index__ = wrapper.__index__;
+ result.__values__ = wrapper.__values__;
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `array` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {number} [size=1] The length of each chunk
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the new array of chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
+ size = 1;
+ } else {
+ size = nativeMax(toInteger(size), 0);
+ }
+ var length = array == null ? 0 : array.length;
+ if (!length || size < 1) {
+ return [];
+ }
+ var index = 0,
+ resIndex = 0,
+ result = Array(nativeCeil(length / size));
+
+ while (index < length) {
+ result[resIndex++] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array == null ? 0 : array.length,
+ resIndex = 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[resIndex++] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates a new array concatenating `array` with any additional arrays
+ * and/or values.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to concatenate.
+ * @param {...*} [values] The values to concatenate.
+ * @returns {Array} Returns the new concatenated array.
+ * @example
+ *
+ * var array = [1];
+ * var other = _.concat(array, 2, [3], [[4]]);
+ *
+ * console.log(other);
+ * // => [1, 2, 3, [4]]
+ *
+ * console.log(array);
+ * // => [1]
+ */
+ function concat() {
+ var length = arguments.length;
+ if (!length) {
+ return [];
+ }
+ var args = Array(length - 1),
+ array = arguments[0],
+ index = length;
+
+ while (index--) {
+ args[index - 1] = arguments[index];
+ }
+ return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
+ }
+
+ /**
+ * Creates an array of `array` values not included in the other given arrays
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons. The order and references of result values are
+ * determined by the first array.
+ *
+ * **Note:** Unlike `_.pullAll`, this method returns a new array.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @see _.without, _.xor
+ * @example
+ *
+ * _.difference([2, 1], [2, 3]);
+ * // => [1]
+ */
+ var difference = baseRest(function(array, values) {
+ return isArrayLikeObject(array)
+ ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
+ : [];
+ });
+
+ /**
+ * This method is like `_.difference` except that it accepts `iteratee` which
+ * is invoked for each element of `array` and `values` to generate the criterion
+ * by which they're compared. The order and references of result values are
+ * determined by the first array. The iteratee is invoked with one argument:
+ * (value).
+ *
+ * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The values to exclude.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+ * // => [1.2]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
+ * // => [{ 'x': 2 }]
+ */
+ var differenceBy = baseRest(function(array, values) {
+ var iteratee = last(values);
+ if (isArrayLikeObject(iteratee)) {
+ iteratee = undefined;
+ }
+ return isArrayLikeObject(array)
+ ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
+ : [];
+ });
+
+ /**
+ * This method is like `_.difference` except that it accepts `comparator`
+ * which is invoked to compare elements of `array` to `values`. The order and
+ * references of result values are determined by the first array. The comparator
+ * is invoked with two arguments: (arrVal, othVal).
+ *
+ * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The values to exclude.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+ *
+ * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
+ * // => [{ 'x': 2, 'y': 1 }]
+ */
+ var differenceWith = baseRest(function(array, values) {
+ var comparator = last(values);
+ if (isArrayLikeObject(comparator)) {
+ comparator = undefined;
+ }
+ return isArrayLikeObject(array)
+ ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
+ : [];
+ });
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.5.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ n = (guard || n === undefined) ? 1 : toInteger(n);
+ return baseSlice(array, n < 0 ? 0 : n, length);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ n = (guard || n === undefined) ? 1 : toInteger(n);
+ n = length - n;
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * invoked with three arguments: (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * _.dropRightWhile(users, function(o) { return !o.active; });
+ * // => objects for ['barney']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
+ * // => objects for ['barney', 'fred']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.dropRightWhile(users, ['active', false]);
+ * // => objects for ['barney']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.dropRightWhile(users, 'active');
+ * // => objects for ['barney', 'fred', 'pebbles']
+ */
+ function dropRightWhile(array, predicate) {
+ return (array && array.length)
+ ? baseWhile(array, getIteratee(predicate, 3), true, true)
+ : [];
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * invoked with three arguments: (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * _.dropWhile(users, function(o) { return !o.active; });
+ * // => objects for ['pebbles']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.dropWhile(users, { 'user': 'barney', 'active': false });
+ * // => objects for ['fred', 'pebbles']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.dropWhile(users, ['active', false]);
+ * // => objects for ['pebbles']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.dropWhile(users, 'active');
+ * // => objects for ['barney', 'fred', 'pebbles']
+ */
+ function dropWhile(array, predicate) {
+ return (array && array.length)
+ ? baseWhile(array, getIteratee(predicate, 3), true)
+ : [];
+ }
+
+ /**
+ * Fills elements of `array` with `value` from `start` up to, but not
+ * including, `end`.
+ *
+ * **Note:** This method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.2.0
+ * @category Array
+ * @param {Array} array The array to fill.
+ * @param {*} value The value to fill `array` with.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _.fill(array, 'a');
+ * console.log(array);
+ * // => ['a', 'a', 'a']
+ *
+ * _.fill(Array(3), 2);
+ * // => [2, 2, 2]
+ *
+ * _.fill([4, 6, 8, 10], '*', 1, 3);
+ * // => [4, '*', '*', 10]
+ */
+ function fill(array, value, start, end) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
+ start = 0;
+ end = length;
+ }
+ return baseFill(array, value, start, end);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for instead of the element itself.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * _.findIndex(users, function(o) { return o.user == 'barney'; });
+ * // => 0
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.findIndex(users, { 'user': 'fred', 'active': false });
+ * // => 1
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.findIndex(users, ['active', false]);
+ * // => 0
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.findIndex(users, 'active');
+ * // => 2
+ */
+ function findIndex(array, predicate, fromIndex) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return -1;
+ }
+ var index = fromIndex == null ? 0 : toInteger(fromIndex);
+ if (index < 0) {
+ index = nativeMax(length + index, 0);
+ }
+ return baseFindIndex(array, getIteratee(predicate, 3), index);
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param {number} [fromIndex=array.length-1] The index to search from.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
+ * // => 2
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.findLastIndex(users, { 'user': 'barney', 'active': true });
+ * // => 0
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.findLastIndex(users, ['active', false]);
+ * // => 2
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, fromIndex) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return -1;
+ }
+ var index = length - 1;
+ if (fromIndex !== undefined) {
+ index = toInteger(fromIndex);
+ index = fromIndex < 0
+ ? nativeMax(length + index, 0)
+ : nativeMin(index, length - 1);
+ }
+ return baseFindIndex(array, getIteratee(predicate, 3), index, true);
+ }
+
+ /**
+ * Flattens `array` a single level deep.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2, [3, [4]], 5]]);
+ * // => [1, 2, [3, [4]], 5]
+ */
+ function flatten(array) {
+ var length = array == null ? 0 : array.length;
+ return length ? baseFlatten(array, 1) : [];
+ }
+
+ /**
+ * Recursively flattens `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2, [3, [4]], 5]]);
+ * // => [1, 2, 3, 4, 5]
+ */
+ function flattenDeep(array) {
+ var length = array == null ? 0 : array.length;
+ return length ? baseFlatten(array, INFINITY) : [];
+ }
+
+ /**
+ * Recursively flatten `array` up to `depth` times.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.4.0
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {number} [depth=1] The maximum recursion depth.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * var array = [1, [2, [3, [4]], 5]];
+ *
+ * _.flattenDepth(array, 1);
+ * // => [1, 2, [3, [4]], 5]
+ *
+ * _.flattenDepth(array, 2);
+ * // => [1, 2, 3, [4], 5]
+ */
+ function flattenDepth(array, depth) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ depth = depth === undefined ? 1 : toInteger(depth);
+ return baseFlatten(array, depth);
+ }
+
+ /**
+ * The inverse of `_.toPairs`; this method returns an object composed
+ * from key-value `pairs`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} pairs The key-value pairs.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.fromPairs([['a', 1], ['b', 2]]);
+ * // => { 'a': 1, 'b': 2 }
+ */
+ function fromPairs(pairs) {
+ var index = -1,
+ length = pairs == null ? 0 : pairs.length,
+ result = {};
+
+ while (++index < length) {
+ var pair = pairs[index];
+ result[pair[0]] = pair[1];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @alias first
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.head([1, 2, 3]);
+ * // => 1
+ *
+ * _.head([]);
+ * // => undefined
+ */
+ function head(array) {
+ return (array && array.length) ? array[0] : undefined;
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons. If `fromIndex` is negative, it's used as the
+ * offset from the end of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 1, 2], 2);
+ * // => 1
+ *
+ * // Search from the `fromIndex`.
+ * _.indexOf([1, 2, 1, 2], 2, 2);
+ * // => 3
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return -1;
+ }
+ var index = fromIndex == null ? 0 : toInteger(fromIndex);
+ if (index < 0) {
+ index = nativeMax(length + index, 0);
+ }
+ return baseIndexOf(array, value, index);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ var length = array == null ? 0 : array.length;
+ return length ? baseSlice(array, 0, -1) : [];
+ }
+
+ /**
+ * Creates an array of unique values that are included in all given arrays
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons. The order and references of result values are
+ * determined by the first array.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of intersecting values.
+ * @example
+ *
+ * _.intersection([2, 1], [2, 3]);
+ * // => [2]
+ */
+ var intersection = baseRest(function(arrays) {
+ var mapped = arrayMap(arrays, castArrayLikeObject);
+ return (mapped.length && mapped[0] === arrays[0])
+ ? baseIntersection(mapped)
+ : [];
+ });
+
+ /**
+ * This method is like `_.intersection` except that it accepts `iteratee`
+ * which is invoked for each element of each `arrays` to generate the criterion
+ * by which they're compared. The order and references of result values are
+ * determined by the first array. The iteratee is invoked with one argument:
+ * (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns the new array of intersecting values.
+ * @example
+ *
+ * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+ * // => [2.1]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }]
+ */
+ var intersectionBy = baseRest(function(arrays) {
+ var iteratee = last(arrays),
+ mapped = arrayMap(arrays, castArrayLikeObject);
+
+ if (iteratee === last(mapped)) {
+ iteratee = undefined;
+ } else {
+ mapped.pop();
+ }
+ return (mapped.length && mapped[0] === arrays[0])
+ ? baseIntersection(mapped, getIteratee(iteratee, 2))
+ : [];
+ });
+
+ /**
+ * This method is like `_.intersection` except that it accepts `comparator`
+ * which is invoked to compare elements of `arrays`. The order and references
+ * of result values are determined by the first array. The comparator is
+ * invoked with two arguments: (arrVal, othVal).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of intersecting values.
+ * @example
+ *
+ * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+ * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+ *
+ * _.intersectionWith(objects, others, _.isEqual);
+ * // => [{ 'x': 1, 'y': 2 }]
+ */
+ var intersectionWith = baseRest(function(arrays) {
+ var comparator = last(arrays),
+ mapped = arrayMap(arrays, castArrayLikeObject);
+
+ comparator = typeof comparator == 'function' ? comparator : undefined;
+ if (comparator) {
+ mapped.pop();
+ }
+ return (mapped.length && mapped[0] === arrays[0])
+ ? baseIntersection(mapped, undefined, comparator)
+ : [];
+ });
+
+ /**
+ * Converts all elements in `array` into a string separated by `separator`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to convert.
+ * @param {string} [separator=','] The element separator.
+ * @returns {string} Returns the joined string.
+ * @example
+ *
+ * _.join(['a', 'b', 'c'], '~');
+ * // => 'a~b~c'
+ */
+ function join(array, separator) {
+ return array == null ? '' : nativeJoin.call(array, separator);
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array == null ? 0 : array.length;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=array.length-1] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 1, 2], 2);
+ * // => 3
+ *
+ * // Search from the `fromIndex`.
+ * _.lastIndexOf([1, 2, 1, 2], 2, 2);
+ * // => 1
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (fromIndex !== undefined) {
+ index = toInteger(fromIndex);
+ index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
+ }
+ return value === value
+ ? strictLastIndexOf(array, value, index)
+ : baseFindIndex(array, baseIsNaN, index, true);
+ }
+
+ /**
+ * Gets the element at index `n` of `array`. If `n` is negative, the nth
+ * element from the end is returned.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.11.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=0] The index of the element to return.
+ * @returns {*} Returns the nth element of `array`.
+ * @example
+ *
+ * var array = ['a', 'b', 'c', 'd'];
+ *
+ * _.nth(array, 1);
+ * // => 'b'
+ *
+ * _.nth(array, -2);
+ * // => 'c';
+ */
+ function nth(array, n) {
+ return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
+ }
+
+ /**
+ * Removes all given values from `array` using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
+ * to remove elements from an array by predicate.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+ *
+ * _.pull(array, 'a', 'c');
+ * console.log(array);
+ * // => ['b', 'b']
+ */
+ var pull = baseRest(pullAll);
+
+ /**
+ * This method is like `_.pull` except that it accepts an array of values to remove.
+ *
+ * **Note:** Unlike `_.difference`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+ *
+ * _.pullAll(array, ['a', 'c']);
+ * console.log(array);
+ * // => ['b', 'b']
+ */
+ function pullAll(array, values) {
+ return (array && array.length && values && values.length)
+ ? basePullAll(array, values)
+ : array;
+ }
+
+ /**
+ * This method is like `_.pullAll` except that it accepts `iteratee` which is
+ * invoked for each element of `array` and `values` to generate the criterion
+ * by which they're compared. The iteratee is invoked with one argument: (value).
+ *
+ * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to remove.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
+ *
+ * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
+ * console.log(array);
+ * // => [{ 'x': 2 }]
+ */
+ function pullAllBy(array, values, iteratee) {
+ return (array && array.length && values && values.length)
+ ? basePullAll(array, values, getIteratee(iteratee, 2))
+ : array;
+ }
+
+ /**
+ * This method is like `_.pullAll` except that it accepts `comparator` which
+ * is invoked to compare elements of `array` to `values`. The comparator is
+ * invoked with two arguments: (arrVal, othVal).
+ *
+ * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.6.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to remove.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
+ *
+ * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
+ * console.log(array);
+ * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
+ */
+ function pullAllWith(array, values, comparator) {
+ return (array && array.length && values && values.length)
+ ? basePullAll(array, values, undefined, comparator)
+ : array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to `indexes` and returns an
+ * array of removed elements.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = ['a', 'b', 'c', 'd'];
+ * var pulled = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => ['a', 'c']
+ *
+ * console.log(pulled);
+ * // => ['b', 'd']
+ */
+ var pullAt = flatRest(function(array, indexes) {
+ var length = array == null ? 0 : array.length,
+ result = baseAt(array, indexes);
+
+ basePullAt(array, arrayMap(indexes, function(index) {
+ return isIndex(index, length) ? +index : index;
+ }).sort(compareAscending));
+
+ return result;
+ });
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is invoked
+ * with three arguments: (value, index, array).
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
+ * to pull elements from an array by value.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) {
+ * return n % 2 == 0;
+ * });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate) {
+ var result = [];
+ if (!(array && array.length)) {
+ return result;
+ }
+ var index = -1,
+ indexes = [],
+ length = array.length;
+
+ predicate = getIteratee(predicate, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ indexes.push(index);
+ }
+ }
+ basePullAt(array, indexes);
+ return result;
+ }
+
+ /**
+ * Reverses `array` so that the first element becomes the last, the second
+ * element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates `array` and is based on
+ * [`Array#reverse`](https://mdn.io/Array/reverse).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _.reverse(array);
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function reverse(array) {
+ return array == null ? array : nativeReverse.call(array);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This method is used instead of
+ * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
+ * returned.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ else {
+ start = start == null ? 0 : toInteger(start);
+ end = end === undefined ? length : toInteger(end);
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ */
+ function sortedIndex(array, value) {
+ return baseSortedIndex(array, value);
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it accepts `iteratee`
+ * which is invoked for `value` and each element of `array` to compute their
+ * sort ranking. The iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * var objects = [{ 'x': 4 }, { 'x': 5 }];
+ *
+ * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+ * // => 0
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
+ * // => 0
+ */
+ function sortedIndexBy(array, value, iteratee) {
+ return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it performs a binary
+ * search on a sorted `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
+ * // => 1
+ */
+ function sortedIndexOf(array, value) {
+ var length = array == null ? 0 : array.length;
+ if (length) {
+ var index = baseSortedIndex(array, value);
+ if (index < length && eq(array[index], value)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value) {
+ return baseSortedIndex(array, value, true);
+ }
+
+ /**
+ * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
+ * which is invoked for `value` and each element of `array` to compute their
+ * sort ranking. The iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * var objects = [{ 'x': 4 }, { 'x': 5 }];
+ *
+ * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+ * // => 1
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
+ * // => 1
+ */
+ function sortedLastIndexBy(array, value, iteratee) {
+ return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
+ }
+
+ /**
+ * This method is like `_.lastIndexOf` except that it performs a binary
+ * search on a sorted `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
+ * // => 3
+ */
+ function sortedLastIndexOf(array, value) {
+ var length = array == null ? 0 : array.length;
+ if (length) {
+ var index = baseSortedIndex(array, value, true) - 1;
+ if (eq(array[index], value)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.uniq` except that it's designed and optimized
+ * for sorted arrays.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * _.sortedUniq([1, 1, 2]);
+ * // => [1, 2]
+ */
+ function sortedUniq(array) {
+ return (array && array.length)
+ ? baseSortedUniq(array)
+ : [];
+ }
+
+ /**
+ * This method is like `_.uniqBy` except that it's designed and optimized
+ * for sorted arrays.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
+ * // => [1.1, 2.3]
+ */
+ function sortedUniqBy(array, iteratee) {
+ return (array && array.length)
+ ? baseSortedUniq(array, getIteratee(iteratee, 2))
+ : [];
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.tail([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function tail(array) {
+ var length = array == null ? 0 : array.length;
+ return length ? baseSlice(array, 1, length) : [];
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ if (!(array && array.length)) {
+ return [];
+ }
+ n = (guard || n === undefined) ? 1 : toInteger(n);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array == null ? 0 : array.length;
+ if (!length) {
+ return [];
+ }
+ n = (guard || n === undefined) ? 1 : toInteger(n);
+ n = length - n;
+ return baseSlice(array, n < 0 ? 0 : n, length);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is invoked with
+ * three arguments: (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': false }
+ * ];
+ *
+ * _.takeRightWhile(users, function(o) { return !o.active; });
+ * // => objects for ['fred', 'pebbles']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
+ * // => objects for ['pebbles']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.takeRightWhile(users, ['active', false]);
+ * // => objects for ['fred', 'pebbles']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.takeRightWhile(users, 'active');
+ * // => []
+ */
+ function takeRightWhile(array, predicate) {
+ return (array && array.length)
+ ? baseWhile(array, getIteratee(predicate, 3), false, true)
+ : [];
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is invoked with
+ * three arguments: (value, index, array).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': false },
+ * { 'user': 'fred', 'active': false },
+ * { 'user': 'pebbles', 'active': true }
+ * ];
+ *
+ * _.takeWhile(users, function(o) { return !o.active; });
+ * // => objects for ['barney', 'fred']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.takeWhile(users, { 'user': 'barney', 'active': false });
+ * // => objects for ['barney']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.takeWhile(users, ['active', false]);
+ * // => objects for ['barney', 'fred']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.takeWhile(users, 'active');
+ * // => []
+ */
+ function takeWhile(array, predicate) {
+ return (array && array.length)
+ ? baseWhile(array, getIteratee(predicate, 3))
+ : [];
+ }
+
+ /**
+ * Creates an array of unique values, in order, from all given arrays using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([2], [1, 2]);
+ * // => [2, 1]
+ */
+ var union = baseRest(function(arrays) {
+ return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
+ });
+
+ /**
+ * This method is like `_.union` except that it accepts `iteratee` which is
+ * invoked for each element of each `arrays` to generate the criterion by
+ * which uniqueness is computed. Result values are chosen from the first
+ * array in which the value occurs. The iteratee is invoked with one argument:
+ * (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.unionBy([2.1], [1.2, 2.3], Math.floor);
+ * // => [2.1, 1.2]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ var unionBy = baseRest(function(arrays) {
+ var iteratee = last(arrays);
+ if (isArrayLikeObject(iteratee)) {
+ iteratee = undefined;
+ }
+ return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
+ });
+
+ /**
+ * This method is like `_.union` except that it accepts `comparator` which
+ * is invoked to compare elements of `arrays`. Result values are chosen from
+ * the first array in which the value occurs. The comparator is invoked
+ * with two arguments: (arrVal, othVal).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+ * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+ *
+ * _.unionWith(objects, others, _.isEqual);
+ * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+ */
+ var unionWith = baseRest(function(arrays) {
+ var comparator = last(arrays);
+ comparator = typeof comparator == 'function' ? comparator : undefined;
+ return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
+ });
+
+ /**
+ * Creates a duplicate-free version of an array, using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons, in which only the first occurrence of each element
+ * is kept. The order of result values is determined by the order they occur
+ * in the array.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * _.uniq([2, 1, 2]);
+ * // => [2, 1]
+ */
+ function uniq(array) {
+ return (array && array.length) ? baseUniq(array) : [];
+ }
+
+ /**
+ * This method is like `_.uniq` except that it accepts `iteratee` which is
+ * invoked for each element in `array` to generate the criterion by which
+ * uniqueness is computed. The order of result values is determined by the
+ * order they occur in the array. The iteratee is invoked with one argument:
+ * (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
+ * // => [2.1, 1.2]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniqBy(array, iteratee) {
+ return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
+ }
+
+ /**
+ * This method is like `_.uniq` except that it accepts `comparator` which
+ * is invoked to compare elements of `array`. The order of result values is
+ * determined by the order they occur in the array.The comparator is invoked
+ * with two arguments: (arrVal, othVal).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
+ *
+ * _.uniqWith(objects, _.isEqual);
+ * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
+ */
+ function uniqWith(array, comparator) {
+ comparator = typeof comparator == 'function' ? comparator : undefined;
+ return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre-zip
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.2.0
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
+ * // => [['a', 1, true], ['b', 2, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['a', 'b'], [1, 2], [true, false]]
+ */
+ function unzip(array) {
+ if (!(array && array.length)) {
+ return [];
+ }
+ var length = 0;
+ array = arrayFilter(array, function(group) {
+ if (isArrayLikeObject(group)) {
+ length = nativeMax(group.length, length);
+ return true;
+ }
+ });
+ return baseTimes(length, function(index) {
+ return arrayMap(array, baseProperty(index));
+ });
+ }
+
+ /**
+ * This method is like `_.unzip` except that it accepts `iteratee` to specify
+ * how regrouped values should be combined. The iteratee is invoked with the
+ * elements of each group: (...group).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.8.0
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @param {Function} [iteratee=_.identity] The function to combine
+ * regrouped values.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
+ * // => [[1, 10, 100], [2, 20, 200]]
+ *
+ * _.unzipWith(zipped, _.add);
+ * // => [3, 30, 300]
+ */
+ function unzipWith(array, iteratee) {
+ if (!(array && array.length)) {
+ return [];
+ }
+ var result = unzip(array);
+ if (iteratee == null) {
+ return result;
+ }
+ return arrayMap(result, function(group) {
+ return apply(iteratee, undefined, group);
+ });
+ }
+
+ /**
+ * Creates an array excluding all given values using
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * **Note:** Unlike `_.pull`, this method returns a new array.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @see _.difference, _.xor
+ * @example
+ *
+ * _.without([2, 1, 2, 3], 1, 2);
+ * // => [3]
+ */
+ var without = baseRest(function(array, values) {
+ return isArrayLikeObject(array)
+ ? baseDifference(array, values)
+ : [];
+ });
+
+ /**
+ * Creates an array of unique values that is the
+ * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
+ * of the given arrays. The order of result values is determined by the order
+ * they occur in the arrays.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.4.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of filtered values.
+ * @see _.difference, _.without
+ * @example
+ *
+ * _.xor([2, 1], [2, 3]);
+ * // => [1, 3]
+ */
+ var xor = baseRest(function(arrays) {
+ return baseXor(arrayFilter(arrays, isArrayLikeObject));
+ });
+
+ /**
+ * This method is like `_.xor` except that it accepts `iteratee` which is
+ * invoked for each element of each `arrays` to generate the criterion by
+ * which by which they're compared. The order of result values is determined
+ * by the order they occur in the arrays. The iteratee is invoked with one
+ * argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+ * // => [1.2, 3.4]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 2 }]
+ */
+ var xorBy = baseRest(function(arrays) {
+ var iteratee = last(arrays);
+ if (isArrayLikeObject(iteratee)) {
+ iteratee = undefined;
+ }
+ return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
+ });
+
+ /**
+ * This method is like `_.xor` except that it accepts `comparator` which is
+ * invoked to compare elements of `arrays`. The order of result values is
+ * determined by the order they occur in the arrays. The comparator is invoked
+ * with two arguments: (arrVal, othVal).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+ * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+ *
+ * _.xorWith(objects, others, _.isEqual);
+ * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+ */
+ var xorWith = baseRest(function(arrays) {
+ var comparator = last(arrays);
+ comparator = typeof comparator == 'function' ? comparator : undefined;
+ return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
+ });
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the
+ * first elements of the given arrays, the second of which contains the
+ * second elements of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['a', 'b'], [1, 2], [true, false]);
+ * // => [['a', 1, true], ['b', 2, false]]
+ */
+ var zip = baseRest(unzip);
+
+ /**
+ * This method is like `_.fromPairs` except that it accepts two arrays,
+ * one of property identifiers and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.4.0
+ * @category Array
+ * @param {Array} [props=[]] The property identifiers.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['a', 'b'], [1, 2]);
+ * // => { 'a': 1, 'b': 2 }
+ */
+ function zipObject(props, values) {
+ return baseZipObject(props || [], values || [], assignValue);
+ }
+
+ /**
+ * This method is like `_.zipObject` except that it supports property paths.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.1.0
+ * @category Array
+ * @param {Array} [props=[]] The property identifiers.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
+ * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
+ */
+ function zipObjectDeep(props, values) {
+ return baseZipObject(props || [], values || [], baseSet);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts `iteratee` to specify
+ * how grouped values should be combined. The iteratee is invoked with the
+ * elements of each group: (...group).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.8.0
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @param {Function} [iteratee=_.identity] The function to combine
+ * grouped values.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
+ * return a + b + c;
+ * });
+ * // => [111, 222]
+ */
+ var zipWith = baseRest(function(arrays) {
+ var length = arrays.length,
+ iteratee = length > 1 ? arrays[length - 1] : undefined;
+
+ iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
+ return unzipWith(arrays, iteratee);
+ });
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` wrapper instance that wraps `value` with explicit method
+ * chain sequences enabled. The result of such sequences must be unwrapped
+ * with `_#value`.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.3.0
+ * @category Seq
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _
+ * .chain(users)
+ * .sortBy('age')
+ * .map(function(o) {
+ * return o.user + ' is ' + o.age;
+ * })
+ * .head()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor
+ * is invoked with one argument; (value). The purpose of this method is to
+ * "tap into" a method chain sequence in order to modify intermediate results.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Seq
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) {
+ * // Mutate input array.
+ * array.pop();
+ * })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor) {
+ interceptor(value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ * The purpose of this method is to "pass thru" values replacing intermediate
+ * results in a method chain sequence.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Seq
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _(' abc ')
+ * .chain()
+ * .trim()
+ * .thru(function(value) {
+ * return [value];
+ * })
+ * .value();
+ * // => ['abc']
+ */
+ function thru(value, interceptor) {
+ return interceptor(value);
+ }
+
+ /**
+ * This method is the wrapper version of `_.at`.
+ *
+ * @name at
+ * @memberOf _
+ * @since 1.0.0
+ * @category Seq
+ * @param {...(string|string[])} [paths] The property paths to pick.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
+ *
+ * _(object).at(['a[0].b.c', 'a[1]']).value();
+ * // => [3, 4]
+ */
+ var wrapperAt = flatRest(function(paths) {
+ var length = paths.length,
+ start = length ? paths[0] : 0,
+ value = this.__wrapped__,
+ interceptor = function(object) { return baseAt(object, paths); };
+
+ if (length > 1 || this.__actions__.length ||
+ !(value instanceof LazyWrapper) || !isIndex(start)) {
+ return this.thru(interceptor);
+ }
+ value = value.slice(start, +start + (length ? 1 : 0));
+ value.__actions__.push({
+ 'func': thru,
+ 'args': [interceptor],
+ 'thisArg': undefined
+ });
+ return new LodashWrapper(value, this.__chain__).thru(function(array) {
+ if (length && !array.length) {
+ array.push(undefined);
+ }
+ return array;
+ });
+ });
+
+ /**
+ * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
+ *
+ * @name chain
+ * @memberOf _
+ * @since 0.1.0
+ * @category Seq
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // A sequence without explicit chaining.
+ * _(users).head();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // A sequence with explicit chaining.
+ * _(users)
+ * .chain()
+ * .head()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Executes the chain sequence and returns the wrapped result.
+ *
+ * @name commit
+ * @memberOf _
+ * @since 3.2.0
+ * @category Seq
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var array = [1, 2];
+ * var wrapped = _(array).push(3);
+ *
+ * console.log(array);
+ * // => [1, 2]
+ *
+ * wrapped = wrapped.commit();
+ * console.log(array);
+ * // => [1, 2, 3]
+ *
+ * wrapped.last();
+ * // => 3
+ *
+ * console.log(array);
+ * // => [1, 2, 3]
+ */
+ function wrapperCommit() {
+ return new LodashWrapper(this.value(), this.__chain__);
+ }
+
+ /**
+ * Gets the next value on a wrapped object following the
+ * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
+ *
+ * @name next
+ * @memberOf _
+ * @since 4.0.0
+ * @category Seq
+ * @returns {Object} Returns the next iterator value.
+ * @example
+ *
+ * var wrapped = _([1, 2]);
+ *
+ * wrapped.next();
+ * // => { 'done': false, 'value': 1 }
+ *
+ * wrapped.next();
+ * // => { 'done': false, 'value': 2 }
+ *
+ * wrapped.next();
+ * // => { 'done': true, 'value': undefined }
+ */
+ function wrapperNext() {
+ if (this.__values__ === undefined) {
+ this.__values__ = toArray(this.value());
+ }
+ var done = this.__index__ >= this.__values__.length,
+ value = done ? undefined : this.__values__[this.__index__++];
+
+ return { 'done': done, 'value': value };
+ }
+
+ /**
+ * Enables the wrapper to be iterable.
+ *
+ * @name Symbol.iterator
+ * @memberOf _
+ * @since 4.0.0
+ * @category Seq
+ * @returns {Object} Returns the wrapper object.
+ * @example
+ *
+ * var wrapped = _([1, 2]);
+ *
+ * wrapped[Symbol.iterator]() === wrapped;
+ * // => true
+ *
+ * Array.from(wrapped);
+ * // => [1, 2]
+ */
+ function wrapperToIterator() {
+ return this;
+ }
+
+ /**
+ * Creates a clone of the chain sequence planting `value` as the wrapped value.
+ *
+ * @name plant
+ * @memberOf _
+ * @since 3.2.0
+ * @category Seq
+ * @param {*} value The value to plant.
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var wrapped = _([1, 2]).map(square);
+ * var other = wrapped.plant([3, 4]);
+ *
+ * other.value();
+ * // => [9, 16]
+ *
+ * wrapped.value();
+ * // => [1, 4]
+ */
+ function wrapperPlant(value) {
+ var result,
+ parent = this;
+
+ while (parent instanceof baseLodash) {
+ var clone = wrapperClone(parent);
+ clone.__index__ = 0;
+ clone.__values__ = undefined;
+ if (result) {
+ previous.__wrapped__ = clone;
+ } else {
+ result = clone;
+ }
+ var previous = clone;
+ parent = parent.__wrapped__;
+ }
+ previous.__wrapped__ = value;
+ return result;
+ }
+
+ /**
+ * This method is the wrapper version of `_.reverse`.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @since 0.1.0
+ * @category Seq
+ * @returns {Object} Returns the new `lodash` wrapper instance.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ var wrapped = value;
+ if (this.__actions__.length) {
+ wrapped = new LazyWrapper(this);
+ }
+ wrapped = wrapped.reverse();
+ wrapped.__actions__.push({
+ 'func': thru,
+ 'args': [reverse],
+ 'thisArg': undefined
+ });
+ return new LodashWrapper(wrapped, this.__chain__);
+ }
+ return this.thru(reverse);
+ }
+
+ /**
+ * Executes the chain sequence to resolve the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @since 0.1.0
+ * @alias toJSON, valueOf
+ * @category Seq
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` thru `iteratee`. The corresponding value of
+ * each key is the number of times the key was returned by `iteratee`. The
+ * iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.5.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([6.1, 4.2, 6.3], Math.floor);
+ * // => { '4': 1, '6': 2 }
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ ++result[key];
+ } else {
+ baseAssignValue(result, key, 1);
+ }
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * Iteration is stopped once `predicate` returns falsey. The predicate is
+ * invoked with three arguments: (value, index|key, collection).
+ *
+ * **Note:** This method returns `true` for
+ * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
+ * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
+ * elements of empty collections.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes'], Boolean);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': false }
+ * ];
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.every(users, { 'user': 'barney', 'active': false });
+ * // => false
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.every(users, ['active', false]);
+ * // => true
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.every(users, 'active');
+ * // => false
+ */
+ function every(collection, predicate, guard) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (guard && isIterateeCall(collection, predicate, guard)) {
+ predicate = undefined;
+ }
+ return func(collection, getIteratee(predicate, 3));
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is invoked with three
+ * arguments: (value, index|key, collection).
+ *
+ * **Note:** Unlike `_.remove`, this method returns a new array.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ * @see _.reject
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false }
+ * ];
+ *
+ * _.filter(users, function(o) { return !o.active; });
+ * // => objects for ['fred']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.filter(users, { 'age': 36, 'active': true });
+ * // => objects for ['barney']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.filter(users, ['active', false]);
+ * // => objects for ['fred']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.filter(users, 'active');
+ * // => objects for ['barney']
+ *
+ * // Combining several predicates using `_.overEvery` or `_.overSome`.
+ * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));
+ * // => objects for ['fred', 'barney']
+ */
+ function filter(collection, predicate) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ return func(collection, getIteratee(predicate, 3));
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is invoked with three
+ * arguments: (value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to inspect.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': true }
+ * ];
+ *
+ * _.find(users, function(o) { return o.age < 40; });
+ * // => object for 'barney'
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.find(users, { 'age': 1, 'active': true });
+ * // => object for 'pebbles'
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.find(users, ['active', false]);
+ * // => object for 'fred'
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.find(users, 'active');
+ * // => object for 'barney'
+ */
+ var find = createFind(findIndex);
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to inspect.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param {number} [fromIndex=collection.length-1] The index to search from.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) {
+ * return n % 2 == 1;
+ * });
+ * // => 3
+ */
+ var findLast = createFind(findLastIndex);
+
+ /**
+ * Creates a flattened array of values by running each element in `collection`
+ * thru `iteratee` and flattening the mapped results. The iteratee is invoked
+ * with three arguments: (value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * function duplicate(n) {
+ * return [n, n];
+ * }
+ *
+ * _.flatMap([1, 2], duplicate);
+ * // => [1, 1, 2, 2]
+ */
+ function flatMap(collection, iteratee) {
+ return baseFlatten(map(collection, iteratee), 1);
+ }
+
+ /**
+ * This method is like `_.flatMap` except that it recursively flattens the
+ * mapped results.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.7.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * function duplicate(n) {
+ * return [[[n, n]]];
+ * }
+ *
+ * _.flatMapDeep([1, 2], duplicate);
+ * // => [1, 1, 2, 2]
+ */
+ function flatMapDeep(collection, iteratee) {
+ return baseFlatten(map(collection, iteratee), INFINITY);
+ }
+
+ /**
+ * This method is like `_.flatMap` except that it recursively flattens the
+ * mapped results up to `depth` times.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.7.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {number} [depth=1] The maximum recursion depth.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * function duplicate(n) {
+ * return [[[n, n]]];
+ * }
+ *
+ * _.flatMapDepth([1, 2], duplicate, 2);
+ * // => [[1, 1], [2, 2]]
+ */
+ function flatMapDepth(collection, iteratee, depth) {
+ depth = depth === undefined ? 1 : toInteger(depth);
+ return baseFlatten(map(collection, iteratee), depth);
+ }
+
+ /**
+ * Iterates over elements of `collection` and invokes `iteratee` for each element.
+ * The iteratee is invoked with three arguments: (value, index|key, collection).
+ * Iteratee functions may exit iteration early by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a "length"
+ * property are iterated like arrays. To avoid this behavior use `_.forIn`
+ * or `_.forOwn` for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @alias each
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @returns {Array|Object} Returns `collection`.
+ * @see _.forEachRight
+ * @example
+ *
+ * _.forEach([1, 2], function(value) {
+ * console.log(value);
+ * });
+ * // => Logs `1` then `2`.
+ *
+ * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
+ * console.log(key);
+ * });
+ * // => Logs 'a' then 'b' (iteration order is not guaranteed).
+ */
+ function forEach(collection, iteratee) {
+ var func = isArray(collection) ? arrayEach : baseEach;
+ return func(collection, getIteratee(iteratee, 3));
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @returns {Array|Object} Returns `collection`.
+ * @see _.forEach
+ * @example
+ *
+ * _.forEachRight([1, 2], function(value) {
+ * console.log(value);
+ * });
+ * // => Logs `2` then `1`.
+ */
+ function forEachRight(collection, iteratee) {
+ var func = isArray(collection) ? arrayEachRight : baseEachRight;
+ return func(collection, getIteratee(iteratee, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` thru `iteratee`. The order of grouped values
+ * is determined by the order they occur in `collection`. The corresponding
+ * value of each key is an array of elements responsible for generating the
+ * key. The iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([6.1, 4.2, 6.3], Math.floor);
+ * // => { '4': [4.2], '6': [6.1, 6.3] }
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ baseAssignValue(result, key, [value]);
+ }
+ });
+
+ /**
+ * Checks if `value` is in `collection`. If `collection` is a string, it's
+ * checked for a substring of `value`, otherwise
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * is used for equality comparisons. If `fromIndex` is negative, it's used as
+ * the offset from the end of `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+ * @returns {boolean} Returns `true` if `value` is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'a': 1, 'b': 2 }, 1);
+ * // => true
+ *
+ * _.includes('abcd', 'bc');
+ * // => true
+ */
+ function includes(collection, value, fromIndex, guard) {
+ collection = isArrayLike(collection) ? collection : values(collection);
+ fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
+
+ var length = collection.length;
+ if (fromIndex < 0) {
+ fromIndex = nativeMax(length + fromIndex, 0);
+ }
+ return isString(collection)
+ ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
+ : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
+ }
+
+ /**
+ * Invokes the method at `path` of each element in `collection`, returning
+ * an array of the results of each invoked method. Any additional arguments
+ * are provided to each invoked method. If `path` is a function, it's invoked
+ * for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Array|Function|string} path The path of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke each method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invokeMap([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ var invokeMap = baseRest(function(collection, path, args) {
+ var index = -1,
+ isFunc = typeof path == 'function',
+ result = isArrayLike(collection) ? Array(collection.length) : [];
+
+ baseEach(collection, function(value) {
+ result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
+ });
+ return result;
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` thru `iteratee`. The corresponding value of
+ * each key is the last element responsible for generating the key. The
+ * iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var array = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.keyBy(array, function(o) {
+ * return String.fromCharCode(o.code);
+ * });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.keyBy(array, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ */
+ var keyBy = createAggregator(function(result, value, key) {
+ baseAssignValue(result, key, value);
+ });
+
+ /**
+ * Creates an array of values by running each element in `collection` thru
+ * `iteratee`. The iteratee is invoked with three arguments:
+ * (value, index|key, collection).
+ *
+ * Many lodash methods are guarded to work as iteratees for methods like
+ * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
+ *
+ * The guarded methods are:
+ * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
+ * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
+ * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
+ * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * _.map([4, 8], square);
+ * // => [16, 64]
+ *
+ * _.map({ 'a': 4, 'b': 8 }, square);
+ * // => [16, 64] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ return func(collection, getIteratee(iteratee, 3));
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it allows specifying the sort
+ * orders of the iteratees to sort by. If `orders` is unspecified, all values
+ * are sorted in ascending order. Otherwise, specify an order of "desc" for
+ * descending or "asc" for ascending sort order of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
+ * The iteratees to sort by.
+ * @param {string[]} [orders] The sort orders of `iteratees`.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 48 },
+ * { 'user': 'barney', 'age': 34 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * // Sort by `user` in ascending order and by `age` in descending order.
+ * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
+ * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
+ */
+ function orderBy(collection, iteratees, orders, guard) {
+ if (collection == null) {
+ return [];
+ }
+ if (!isArray(iteratees)) {
+ iteratees = iteratees == null ? [] : [iteratees];
+ }
+ orders = guard ? undefined : orders;
+ if (!isArray(orders)) {
+ orders = orders == null ? [] : [orders];
+ }
+ return baseOrderBy(collection, iteratees, orders);
+ }
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, the second of which
+ * contains elements `predicate` returns falsey for. The predicate is
+ * invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.partition(users, function(o) { return o.active; });
+ * // => objects for [['fred'], ['barney', 'pebbles']]
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.partition(users, { 'age': 1, 'active': false });
+ * // => objects for [['pebbles'], ['barney', 'fred']]
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.partition(users, ['active', false]);
+ * // => objects for [['barney', 'pebbles'], ['fred']]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.partition(users, 'active');
+ * // => objects for [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` thru `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not given, the first element of `collection` is used as the initial
+ * value. The iteratee is invoked with four arguments:
+ * (accumulator, value, index|key, collection).
+ *
+ * Many lodash methods are guarded to work as iteratees for methods like
+ * `_.reduce`, `_.reduceRight`, and `_.transform`.
+ *
+ * The guarded methods are:
+ * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
+ * and `sortBy`
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @returns {*} Returns the accumulated value.
+ * @see _.reduceRight
+ * @example
+ *
+ * _.reduce([1, 2], function(sum, n) {
+ * return sum + n;
+ * }, 0);
+ * // => 3
+ *
+ * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
+ * (result[value] || (result[value] = [])).push(key);
+ * return result;
+ * }, {});
+ * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator) {
+ var func = isArray(collection) ? arrayReduce : baseReduce,
+ initAccum = arguments.length < 3;
+
+ return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @returns {*} Returns the accumulated value.
+ * @see _.reduce
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ *
+ * _.reduceRight(array, function(flattened, other) {
+ * return flattened.concat(other);
+ * }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce,
+ initAccum = arguments.length < 3;
+
+ return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ * @see _.filter
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * _.reject(users, function(o) { return !o.active; });
+ * // => objects for ['fred']
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.reject(users, { 'age': 40, 'active': true });
+ * // => objects for ['barney']
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.reject(users, ['active', false]);
+ * // => objects for ['fred']
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.reject(users, 'active');
+ * // => objects for ['barney']
+ */
+ function reject(collection, predicate) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ return func(collection, negate(getIteratee(predicate, 3)));
+ }
+
+ /**
+ * Gets a random element from `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to sample.
+ * @returns {*} Returns the random element.
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ */
+ function sample(collection) {
+ var func = isArray(collection) ? arraySample : baseSample;
+ return func(collection);
+ }
+
+ /**
+ * Gets `n` random elements at unique keys from `collection` up to the
+ * size of `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to sample.
+ * @param {number} [n=1] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Array} Returns the random elements.
+ * @example
+ *
+ * _.sampleSize([1, 2, 3], 2);
+ * // => [3, 1]
+ *
+ * _.sampleSize([1, 2, 3], 4);
+ * // => [2, 3, 1]
+ */
+ function sampleSize(collection, n, guard) {
+ if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
+ n = 1;
+ } else {
+ n = toInteger(n);
+ }
+ var func = isArray(collection) ? arraySampleSize : baseSampleSize;
+ return func(collection, n);
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the
+ * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ var func = isArray(collection) ? arrayShuffle : baseShuffle;
+ return func(collection);
+ }
+
+ /**
+ * Gets the size of `collection` by returning its length for array-like
+ * values or the number of own enumerable string keyed properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the collection size.
+ * @example
+ *
+ * _.size([1, 2, 3]);
+ * // => 3
+ *
+ * _.size({ 'a': 1, 'b': 2 });
+ * // => 2
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ if (collection == null) {
+ return 0;
+ }
+ if (isArrayLike(collection)) {
+ return isString(collection) ? stringSize(collection) : collection.length;
+ }
+ var tag = getTag(collection);
+ if (tag == mapTag || tag == setTag) {
+ return collection.size;
+ }
+ return baseKeys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * Iteration is stopped once `predicate` returns truthy. The predicate is
+ * invoked with three arguments: (value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {Function} [predicate=_.identity] The function invoked per iteration.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'active': true },
+ * { 'user': 'fred', 'active': false }
+ * ];
+ *
+ * // The `_.matches` iteratee shorthand.
+ * _.some(users, { 'user': 'barney', 'active': false });
+ * // => false
+ *
+ * // The `_.matchesProperty` iteratee shorthand.
+ * _.some(users, ['active', false]);
+ * // => true
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.some(users, 'active');
+ * // => true
+ */
+ function some(collection, predicate, guard) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (guard && isIterateeCall(collection, predicate, guard)) {
+ predicate = undefined;
+ }
+ return func(collection, getIteratee(predicate, 3));
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection thru each iteratee. This method
+ * performs a stable sort, that is, it preserves the original sort order of
+ * equal elements. The iteratees are invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Collection
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {...(Function|Function[])} [iteratees=[_.identity]]
+ * The iteratees to sort by.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 48 },
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 30 },
+ * { 'user': 'barney', 'age': 34 }
+ * ];
+ *
+ * _.sortBy(users, [function(o) { return o.user; }]);
+ * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 30]]
+ *
+ * _.sortBy(users, ['user', 'age']);
+ * // => objects for [['barney', 34], ['barney', 36], ['fred', 30], ['fred', 48]]
+ */
+ var sortBy = baseRest(function(collection, iteratees) {
+ if (collection == null) {
+ return [];
+ }
+ var length = iteratees.length;
+ if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
+ iteratees = [];
+ } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
+ iteratees = [iteratees[0]];
+ }
+ return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
+ });
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the timestamp of the number of milliseconds that have elapsed since
+ * the Unix epoch (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @since 2.4.0
+ * @category Date
+ * @returns {number} Returns the timestamp.
+ * @example
+ *
+ * _.defer(function(stamp) {
+ * console.log(_.now() - stamp);
+ * }, _.now());
+ * // => Logs the number of milliseconds it took for the deferred invocation.
+ */
+ var now = ctxNow || function() {
+ return root.Date.now();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it's called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => Logs 'done saving!' after the two async saves have completed.
+ */
+ function after(n, func) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ n = toInteger(n);
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func`, with up to `n` arguments,
+ * ignoring any additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Function} Returns the new capped function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ n = guard ? undefined : n;
+ n = (func && n == null) ? func.length : n;
+ return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it's called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery(element).on('click', _.before(5, addContactToList));
+ * // => Allows adding up to 4 contacts to the list.
+ */
+ function before(n, func) {
+ var result;
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ n = toInteger(n);
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ }
+ if (n <= 1) {
+ func = undefined;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and `partials` prepended to the arguments it receives.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * function greet(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // Bound with placeholders.
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ var bind = baseRest(function(func, thisArg, partials) {
+ var bitmask = WRAP_BIND_FLAG;
+ if (partials.length) {
+ var holders = replaceHolders(partials, getHolder(bind));
+ bitmask |= WRAP_PARTIAL_FLAG;
+ }
+ return createWrap(func, bitmask, thisArg, partials, holders);
+ });
+
+ /**
+ * Creates a function that invokes the method at `object[key]` with `partials`
+ * prepended to the arguments it receives.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist. See
+ * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.10.0
+ * @category Function
+ * @param {Object} object The object to invoke the method on.
+ * @param {string} key The key of the method.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // Bound with placeholders.
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ var bindKey = baseRest(function(object, key, partials) {
+ var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
+ if (partials.length) {
+ var holders = replaceHolders(partials, getHolder(bindKey));
+ bitmask |= WRAP_PARTIAL_FLAG;
+ }
+ return createWrap(key, bitmask, object, partials, holders);
+ });
+
+ /**
+ * Creates a function that accepts arguments of `func` and either invokes
+ * `func` returning its result, if at least `arity` number of arguments have
+ * been provided, or returns a function that accepts the remaining `func`
+ * arguments, and so on. The arity of `func` may be specified if `func.length`
+ * is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method doesn't set the "length" property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.0.0
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // Curried with placeholders.
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ function curry(func, arity, guard) {
+ arity = guard ? undefined : arity;
+ var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
+ result.placeholder = curry.placeholder;
+ return result;
+ }
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method doesn't set the "length" property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // Curried with placeholders.
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ function curryRight(func, arity, guard) {
+ arity = guard ? undefined : arity;
+ var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
+
+ /**
+ * Creates a debounced function that delays invoking `func` until after `wait`
+ * milliseconds have elapsed since the last time the debounced function was
+ * invoked. The debounced function comes with a `cancel` method to cancel
+ * delayed `func` invocations and a `flush` method to immediately invoke them.
+ * Provide `options` to indicate whether `func` should be invoked on the
+ * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
+ * with the last arguments provided to the debounced function. Subsequent
+ * calls to the debounced function return the result of the last `func`
+ * invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the debounced function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} [wait=0] The number of milliseconds to delay.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=false]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {number} [options.maxWait]
+ * The maximum time `func` is allowed to be delayed before it's invoked.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // Avoid costly calculations while the window size is in flux.
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // Invoke `sendMail` when clicked, debouncing subsequent calls.
+ * jQuery(element).on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
+ * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', debounced);
+ *
+ * // Cancel the trailing debounced invocation.
+ * jQuery(window).on('popstate', debounced.cancel);
+ */
+ function debounce(func, wait, options) {
+ var lastArgs,
+ lastThis,
+ maxWait,
+ result,
+ timerId,
+ lastCallTime,
+ lastInvokeTime = 0,
+ leading = false,
+ maxing = false,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = toNumber(wait) || 0;
+ if (isObject(options)) {
+ leading = !!options.leading;
+ maxing = 'maxWait' in options;
+ maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+
+ function invokeFunc(time) {
+ var args = lastArgs,
+ thisArg = lastThis;
+
+ lastArgs = lastThis = undefined;
+ lastInvokeTime = time;
+ result = func.apply(thisArg, args);
+ return result;
+ }
+
+ function leadingEdge(time) {
+ // Reset any `maxWait` timer.
+ lastInvokeTime = time;
+ // Start the timer for the trailing edge.
+ timerId = setTimeout(timerExpired, wait);
+ // Invoke the leading edge.
+ return leading ? invokeFunc(time) : result;
+ }
+
+ function remainingWait(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime,
+ timeWaiting = wait - timeSinceLastCall;
+
+ return maxing
+ ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
+ : timeWaiting;
+ }
+
+ function shouldInvoke(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime;
+
+ // Either this is the first call, activity has stopped and we're at the
+ // trailing edge, the system time has gone backwards and we're treating
+ // it as the trailing edge, or we've hit the `maxWait` limit.
+ return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
+ (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
+ }
+
+ function timerExpired() {
+ var time = now();
+ if (shouldInvoke(time)) {
+ return trailingEdge(time);
+ }
+ // Restart the timer.
+ timerId = setTimeout(timerExpired, remainingWait(time));
+ }
+
+ function trailingEdge(time) {
+ timerId = undefined;
+
+ // Only invoke if we have `lastArgs` which means `func` has been
+ // debounced at least once.
+ if (trailing && lastArgs) {
+ return invokeFunc(time);
+ }
+ lastArgs = lastThis = undefined;
+ return result;
+ }
+
+ function cancel() {
+ if (timerId !== undefined) {
+ clearTimeout(timerId);
+ }
+ lastInvokeTime = 0;
+ lastArgs = lastCallTime = lastThis = timerId = undefined;
+ }
+
+ function flush() {
+ return timerId === undefined ? result : trailingEdge(now());
+ }
+
+ function debounced() {
+ var time = now(),
+ isInvoking = shouldInvoke(time);
+
+ lastArgs = arguments;
+ lastThis = this;
+ lastCallTime = time;
+
+ if (isInvoking) {
+ if (timerId === undefined) {
+ return leadingEdge(lastCallTime);
+ }
+ if (maxing) {
+ // Handle invocations in a tight loop.
+ clearTimeout(timerId);
+ timerId = setTimeout(timerExpired, wait);
+ return invokeFunc(lastCallTime);
+ }
+ }
+ if (timerId === undefined) {
+ timerId = setTimeout(timerExpired, wait);
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ debounced.flush = flush;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it's invoked.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke `func` with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) {
+ * console.log(text);
+ * }, 'deferred');
+ * // => Logs 'deferred' after one millisecond.
+ */
+ var defer = baseRest(function(func, args) {
+ return baseDelay(func, 1, args);
+ });
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it's invoked.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke `func` with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) {
+ * console.log(text);
+ * }, 1000, 'later');
+ * // => Logs 'later' after one second.
+ */
+ var delay = baseRest(function(func, wait, args) {
+ return baseDelay(func, toNumber(wait) || 0, args);
+ });
+
+ /**
+ * Creates a function that invokes `func` with arguments reversed.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Function
+ * @param {Function} func The function to flip arguments for.
+ * @returns {Function} Returns the new flipped function.
+ * @example
+ *
+ * var flipped = _.flip(function() {
+ * return _.toArray(arguments);
+ * });
+ *
+ * flipped('a', 'b', 'c', 'd');
+ * // => ['d', 'c', 'b', 'a']
+ */
+ function flip(func) {
+ return createWrap(func, WRAP_FLIP_FLAG);
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided, it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is used as the map cache key. The `func`
+ * is invoked with the `this` binding of the memoized function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `clear`, `delete`, `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoized function.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2 };
+ * var other = { 'c': 3, 'd': 4 };
+ *
+ * var values = _.memoize(_.values);
+ * values(object);
+ * // => [1, 2]
+ *
+ * values(other);
+ * // => [3, 4]
+ *
+ * object.a = 2;
+ * values(object);
+ * // => [1, 2]
+ *
+ * // Modify the result cache.
+ * values.cache.set(object, ['a', 'b']);
+ * values(object);
+ * // => ['a', 'b']
+ *
+ * // Replace `_.memoize.Cache`.
+ * _.memoize.Cache = WeakMap;
+ */
+ function memoize(func, resolver) {
+ if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var args = arguments,
+ key = resolver ? resolver.apply(this, args) : args[0],
+ cache = memoized.cache;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, args);
+ memoized.cache = cache.set(key, result) || cache;
+ return result;
+ };
+ memoized.cache = new (memoize.Cache || MapCache);
+ return memoized;
+ }
+
+ // Expose `MapCache`.
+ memoize.Cache = MapCache;
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new negated function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (typeof predicate != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var args = arguments;
+ switch (args.length) {
+ case 0: return !predicate.call(this);
+ case 1: return !predicate.call(this, args[0]);
+ case 2: return !predicate.call(this, args[0], args[1]);
+ case 3: return !predicate.call(this, args[0], args[1], args[2]);
+ }
+ return !predicate.apply(this, args);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first invocation. The `func` is
+ * invoked with the `this` binding and arguments of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // => `createApplication` is invoked once
+ */
+ function once(func) {
+ return before(2, func);
+ }
+
+ /**
+ * Creates a function that invokes `func` with its arguments transformed.
+ *
+ * @static
+ * @since 4.0.0
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to wrap.
+ * @param {...(Function|Function[])} [transforms=[_.identity]]
+ * The argument transforms.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function doubled(n) {
+ * return n * 2;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var func = _.overArgs(function(x, y) {
+ * return [x, y];
+ * }, [square, doubled]);
+ *
+ * func(9, 3);
+ * // => [81, 6]
+ *
+ * func(10, 5);
+ * // => [100, 10]
+ */
+ var overArgs = castRest(function(func, transforms) {
+ transforms = (transforms.length == 1 && isArray(transforms[0]))
+ ? arrayMap(transforms[0], baseUnary(getIteratee()))
+ : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
+
+ var funcsLength = transforms.length;
+ return baseRest(function(args) {
+ var index = -1,
+ length = nativeMin(args.length, funcsLength);
+
+ while (++index < length) {
+ args[index] = transforms[index].call(this, args[index]);
+ }
+ return apply(func, this, args);
+ });
+ });
+
+ /**
+ * Creates a function that invokes `func` with `partials` prepended to the
+ * arguments it receives. This method is like `_.bind` except it does **not**
+ * alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method doesn't set the "length" property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.2.0
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * function greet(greeting, name) {
+ * return greeting + ' ' + name;
+ * }
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // Partially applied with placeholders.
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ var partial = baseRest(function(func, partials) {
+ var holders = replaceHolders(partials, getHolder(partial));
+ return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
+ });
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to the arguments it receives.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method doesn't set the "length" property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.0.0
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [partials] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * function greet(greeting, name) {
+ * return greeting + ' ' + name;
+ * }
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // Partially applied with placeholders.
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ var partialRight = baseRest(function(func, partials) {
+ var holders = replaceHolders(partials, getHolder(partialRight));
+ return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
+ });
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified `indexes` where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, [2, 0, 1]);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ */
+ var rearg = flatRest(function(func, indexes) {
+ return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
+ });
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * created function and arguments from `start` and beyond provided as
+ * an array.
+ *
+ * **Note:** This method is based on the
+ * [rest parameter](https://mdn.io/rest_parameters).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Function
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.rest(function(what, names) {
+ * return what + ' ' + _.initial(names).join(', ') +
+ * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+ * });
+ *
+ * say('hello', 'fred', 'barney', 'pebbles');
+ * // => 'hello fred, barney, & pebbles'
+ */
+ function rest(func, start) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ start = start === undefined ? start : toInteger(start);
+ return baseRest(func, start);
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * create function and an array of arguments much like
+ * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
+ *
+ * **Note:** This method is based on the
+ * [spread operator](https://mdn.io/spread_operator).
+ *
+ * @static
+ * @memberOf _
+ * @since 3.2.0
+ * @category Function
+ * @param {Function} func The function to spread arguments over.
+ * @param {number} [start=0] The start position of the spread.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.spread(function(who, what) {
+ * return who + ' says ' + what;
+ * });
+ *
+ * say(['fred', 'hello']);
+ * // => 'fred says hello'
+ *
+ * var numbers = Promise.all([
+ * Promise.resolve(40),
+ * Promise.resolve(36)
+ * ]);
+ *
+ * numbers.then(_.spread(function(x, y) {
+ * return x + y;
+ * }));
+ * // => a Promise of 76
+ */
+ function spread(func, start) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ start = start == null ? 0 : nativeMax(toInteger(start), 0);
+ return baseRest(function(args) {
+ var array = args[start],
+ otherArgs = castSlice(args, 0, start);
+
+ if (array) {
+ arrayPush(otherArgs, array);
+ }
+ return apply(func, this, otherArgs);
+ });
+ }
+
+ /**
+ * Creates a throttled function that only invokes `func` at most once per
+ * every `wait` milliseconds. The throttled function comes with a `cancel`
+ * method to cancel delayed `func` invocations and a `flush` method to
+ * immediately invoke them. Provide `options` to indicate whether `func`
+ * should be invoked on the leading and/or trailing edge of the `wait`
+ * timeout. The `func` is invoked with the last arguments provided to the
+ * throttled function. Subsequent calls to the throttled function return the
+ * result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the throttled function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=true]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // Avoid excessively updating the position while scrolling.
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
+ * jQuery(element).on('click', throttled);
+ *
+ * // Cancel the trailing throttled invocation.
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ return debounce(func, wait, {
+ 'leading': leading,
+ 'maxWait': wait,
+ 'trailing': trailing
+ });
+ }
+
+ /**
+ * Creates a function that accepts up to one argument, ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @returns {Function} Returns the new capped function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.unary(parseInt));
+ * // => [6, 8, 10]
+ */
+ function unary(func) {
+ return ary(func, 1);
+ }
+
+ /**
+ * Creates a function that provides `value` to `wrapper` as its first
+ * argument. Any additional arguments provided to the function are appended
+ * to those provided to the `wrapper`. The wrapper is invoked with the `this`
+ * binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} [wrapper=identity] The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '