UNPKG

@ionic/angular

Version:

Angular specific wrappers for @ionic/core

257 lines 28.6 kB
import { DOCUMENT } from '@angular/common'; import { Inject, Injectable } from '@angular/core'; import { getPlatforms, isPlatform } from '@ionic/core/components'; import { Subject } from 'rxjs'; import * as i0 from "@angular/core"; export class Platform { doc; _readyPromise; win; /** * @hidden */ backButton = new Subject(); /** * The keyboardDidShow event emits when the * on-screen keyboard is presented. */ keyboardDidShow = new Subject(); /** * The keyboardDidHide event emits when the * on-screen keyboard is hidden. */ keyboardDidHide = new Subject(); /** * The pause event emits when the native platform puts the application * into the background, typically when the user switches to a different * application. This event would emit when a Cordova app is put into * the background, however, it would not fire on a standard web browser. */ pause = new Subject(); /** * The resume event emits when the native platform pulls the application * out from the background. This event would emit when a Cordova app comes * out from the background, however, it would not fire on a standard web browser. */ resume = new Subject(); /** * The resize event emits when the browser window has changed dimensions. This * could be from a browser window being physically resized, or from a device * changing orientation. */ resize = new Subject(); constructor(doc, zone) { this.doc = doc; zone.run(() => { this.win = doc.defaultView; this.backButton.subscribeWithPriority = function (priority, callback) { return this.subscribe((ev) => { return ev.register(priority, (processNextHandler) => zone.run(() => callback(processNextHandler))); }); }; proxyEvent(this.pause, doc, 'pause', zone); proxyEvent(this.resume, doc, 'resume', zone); proxyEvent(this.backButton, doc, 'ionBackButton', zone); proxyEvent(this.resize, this.win, 'resize', zone); proxyEvent(this.keyboardDidShow, this.win, 'ionKeyboardDidShow', zone); proxyEvent(this.keyboardDidHide, this.win, 'ionKeyboardDidHide', zone); let readyResolve; this._readyPromise = new Promise((res) => { readyResolve = res; }); if (this.win?.['cordova']) { doc.addEventListener('deviceready', () => { readyResolve('cordova'); }, { once: true }); } else { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion readyResolve('dom'); } }); } /** * @returns returns true/false based on platform. * @description * Depending on the platform the user is on, `is(platformName)` will * return `true` or `false`. Note that the same app can return `true` * for more than one platform name. For example, an app running from * an iPad would return `true` for the platform names: `mobile`, * `ios`, `ipad`, and `tablet`. Additionally, if the app was running * from Cordova then `cordova` would be true, and if it was running * from a web browser on the iPad then `mobileweb` would be `true`. * * ``` * import { Platform } from 'ionic-angular'; * * @Component({...}) * export MyPage { * constructor(public platform: Platform) { * if (this.platform.is('ios')) { * // This will only print when on iOS * console.log('I am an iOS device!'); * } * } * } * ``` * * | Platform Name | Description | * |-----------------|------------------------------------| * | android | on a device running Android. | * | capacitor | on a device running Capacitor. | * | cordova | on a device running Cordova. | * | ios | on a device running iOS. | * | ipad | on an iPad device. | * | iphone | on an iPhone device. | * | phablet | on a phablet device. | * | tablet | on a tablet device. | * | electron | in Electron on a desktop device. | * | pwa | as a PWA app. | * | mobile | on a mobile device. | * | mobileweb | on a mobile device in a browser. | * | desktop | on a desktop device. | * | hybrid | is a cordova or capacitor app. | * */ is(platformName) { return isPlatform(this.win, platformName); } /** * @returns the array of platforms * @description * Depending on what device you are on, `platforms` can return multiple values. * Each possible value is a hierarchy of platforms. For example, on an iPhone, * it would return `mobile`, `ios`, and `iphone`. * * ``` * import { Platform } from 'ionic-angular'; * * @Component({...}) * export MyPage { * constructor(public platform: Platform) { * // This will print an array of the current platforms * console.log(this.platform.platforms()); * } * } * ``` */ platforms() { return getPlatforms(this.win); } /** * Returns a promise when the platform is ready and native functionality * can be called. If the app is running from within a web browser, then * the promise will resolve when the DOM is ready. When the app is running * from an application engine such as Cordova, then the promise will * resolve when Cordova triggers the `deviceready` event. * * The resolved value is the `readySource`, which states which platform * ready was used. For example, when Cordova is ready, the resolved ready * source is `cordova`. The default ready source value will be `dom`. The * `readySource` is useful if different logic should run depending on the * platform the app is running from. For example, only Cordova can execute * the status bar plugin, so the web should not run status bar plugin logic. * * ``` * import { Component } from '@angular/core'; * import { Platform } from 'ionic-angular'; * * @Component({...}) * export MyApp { * constructor(public platform: Platform) { * this.platform.ready().then((readySource) => { * console.log('Platform ready from', readySource); * // Platform now ready, execute any required native code * }); * } * } * ``` */ ready() { return this._readyPromise; } /** * Returns if this app is using right-to-left language direction or not. * We recommend the app's `index.html` file already has the correct `dir` * attribute value set, such as `<html dir="ltr">` or `<html dir="rtl">`. * [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir) */ get isRTL() { return this.doc.dir === 'rtl'; } /** * Get the query string parameter */ getQueryParam(key) { return readQueryParam(this.win.location.href, key); } /** * Returns `true` if the app is in landscape mode. */ isLandscape() { return !this.isPortrait(); } /** * Returns `true` if the app is in portrait mode. */ isPortrait() { return this.win.matchMedia?.('(orientation: portrait)').matches; } testUserAgent(expression) { const nav = this.win.navigator; return !!(nav?.userAgent && nav.userAgent.indexOf(expression) >= 0); } /** * Get the current url. */ url() { return this.win.location.href; } /** * Gets the width of the platform's viewport using `window.innerWidth`. */ width() { return this.win.innerWidth; } /** * Gets the height of the platform's viewport using `window.innerHeight`. */ height() { return this.win.innerHeight; } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: Platform, deps: [{ token: DOCUMENT }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: Platform, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: Platform, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i0.NgZone }]; } }); const readQueryParam = (url, key) => { key = key.replace(/[[\]\\]/g, '\\$&'); const regex = new RegExp('[\\?&]' + key + '=([^&#]*)'); const results = regex.exec(url); return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null; }; const proxyEvent = (emitter, el, eventName, zone) => { if (el) { el.addEventListener(eventName, (ev) => { /** * `zone.run` is required to make sure that we are running inside the Angular zone * at all times. This is necessary since an app that has Capacitor will * override the `document.addEventListener` with its own implementation. * The override causes the event to no longer be in the Angular zone. */ zone.run(() => { // ?? cordova might emit "null" events const value = ev != null ? ev.detail : undefined; emitter.next(value); }); }); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhdGZvcm0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb21tb24vc3JjL3Byb3ZpZGVycy9wbGF0Zm9ybS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFVLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUVsRSxPQUFPLEVBQWdCLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQzs7QUFjN0MsTUFBTSxPQUFPLFFBQVE7SUEyQ21CO0lBMUM5QixhQUFhLENBQWtCO0lBQy9CLEdBQUcsQ0FBTTtJQUVqQjs7T0FFRztJQUNILFVBQVUsR0FBRyxJQUFJLE9BQU8sRUFBOEMsQ0FBQztJQUV2RTs7O09BR0c7SUFDSCxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXVCLENBQUM7SUFFckQ7OztPQUdHO0lBQ0gsZUFBZSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7SUFFdEM7Ozs7O09BS0c7SUFDSCxLQUFLLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztJQUU1Qjs7OztPQUlHO0lBQ0gsTUFBTSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7SUFFN0I7Ozs7T0FJRztJQUNILE1BQU0sR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO0lBRTdCLFlBQXNDLEdBQVEsRUFBRSxJQUFZO1FBQXRCLFFBQUcsR0FBSCxHQUFHLENBQUs7UUFDNUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7WUFDWixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxXQUFXLENBQUM7WUFDM0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxxQkFBcUIsR0FBRyxVQUFVLFFBQVEsRUFBRSxRQUFRO2dCQUNsRSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMs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QUVGLE1BQU0sVUFBVSxHQUFHLENBQUksT0FBbUIsRUFBRSxFQUFlLEVBQUUsU0FBaUIsRUFBRSxJQUFZLEVBQUUsRUFBRTtJQUM5RixJQUFJLEVBQUUsRUFBRTtRQUNOLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRTtZQUNwQzs7Ozs7ZUFLRztZQUNILElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO2dCQUNaLHNDQUFzQztnQkFDdEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUUsRUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUMxRCxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3RCLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7S0FDSjtBQUNILENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERPQ1VNRU5UIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IE5nWm9uZSwgSW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBnZXRQbGF0Zm9ybXMsIGlzUGxhdGZvcm0gfSBmcm9tICdAaW9uaWMvY29yZS9jb21wb25lbnRzJztcbmltcG9ydCB0eXBlIHsgQmFja0J1dHRvbkV2ZW50RGV0YWlsLCBLZXlib2FyZEV2ZW50RGV0YWlsLCBQbGF0Zm9ybXMgfSBmcm9tICdAaW9uaWMvY29yZS9jb21wb25lbnRzJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG4vLyBUT0RPKEZXLTI4MjcpOiB0eXBlc1xuXG5leHBvcnQgaW50ZXJmYWNlIEJhY2tCdXR0b25FbWl0dGVyIGV4dGVuZHMgU3ViamVjdDxCYWNrQnV0dG9uRXZlbnREZXRhaWw+IHtcbiAgc3Vic2NyaWJlV2l0aFByaW9yaXR5KFxuICAgIHByaW9yaXR5OiBudW1iZXIsXG4gICAgY2FsbGJhY2s6IChwcm9jZXNzTmV4dEhhbmRsZXI6ICgpID0+IHZvaWQpID0+IFByb21pc2U8YW55PiB8IHZvaWRcbiAgKTogU3Vic2NyaXB0aW9uO1xufVxuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgUGxhdGZvcm0ge1xuICBwcml2YXRlIF9yZWFkeVByb21pc2U6IFByb21pc2U8c3RyaW5nPjtcbiAgcHJpdmF0ZSB3aW46IGFueTtcblxuICAvKipcbiAgICogQGhpZGRlblxuICAgKi9cbiAgYmFja0J1dHRvbiA9IG5ldyBTdWJqZWN0PEJhY2tCdXR0b25FdmVudERldGFpbD4oKSBhcyBCYWNrQnV0dG9uRW1pdHRlcjtcblxuICAvKipcbiAgICogVGhlIGtleWJvYXJkRGlkU2hvdyBldmVudCBlbWl0cyB3aGVuIHRoZVxuICAgKiBvbi1zY3JlZW4ga2V5Ym9hcmQgaXMgcHJlc2VudGVkLlxuICAgKi9cbiAga2V5Ym9hcmREaWRTaG93ID0gbmV3IFN1YmplY3Q8S2V5Ym9hcmRFdmVudERldGFpbD4oKTtcblxuICAvKipcbiAgICogVGhlIGtleWJvYXJkRGlkSGlkZSBldmVudCBlbWl0cyB3aGVuIHRoZVxuICAgKiBvbi1zY3JlZW4ga2V5Ym9hcmQgaXMgaGlkZGVuLlxuICAgKi9cbiAga2V5Ym9hcmREaWRIaWRlID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAvKipcbiAgICogVGhlIHBhdXNlIGV2ZW50IGVtaXRzIHdoZW4gdGhlIG5hdGl2ZSBwbGF0Zm9ybSBwdXRzIHRoZSBhcHBsaWNhdGlvblxuICAgKiBpbnRvIHRoZSBiYWNrZ3JvdW5kLCB0eXBpY2FsbHkgd2hlbiB0aGUgdXNlciBzd2l0Y2hlcyB0byBhIGRpZmZlcmVudFxuICAgKiBhcHBsaWNhdGlvbi4gVGhpcyBldmVudCB3b3VsZCBlbWl0IHdoZW4gYSBDb3Jkb3ZhIGFwcCBpcyBwdXQgaW50b1xuICAgKiB0aGUgYmFja2dyb3VuZCwgaG93ZXZlciwgaXQgd291bGQgbm90IGZpcmUgb24gYSBzdGFuZGFyZCB3ZWIgYnJvd3Nlci5cbiAgICovXG4gIHBhdXNlID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAvKipcbiAgICogVGhlIHJlc3VtZSBldmVudCBlbWl0cyB3aGVuIHRoZSBuYXRpdmUgcGxhdGZvcm0gcHVsbHMgdGhlIGFwcGxpY2F0aW9uXG4gICAqIG91dCBmcm9tIHRoZSBiYWNrZ3JvdW5kLiBUaGlzIGV2ZW50IHdvdWxkIGVtaXQgd2hlbiBhIENvcmRvdmEgYXBwIGNvbWVzXG4gICAqIG91dCBmcm9tIHRoZSBiYWNrZ3JvdW5kLCBob3dldmVyLCBpdCB3b3VsZCBub3QgZmlyZSBvbiBhIHN0YW5kYXJkIHdlYiBicm93c2VyLlxuICAgKi9cbiAgcmVzdW1lID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAvKipcbiAgICogVGhlIHJlc2l6ZSBldmVudCBlbWl0cyB3aGVuIHRoZSBicm93c2VyIHdpbmRvdyBoYXMgY2hhbmdlZCBkaW1lbnNpb25zLiBUaGlzXG4gICAqIGNvdWxkIGJlIGZyb20gYSBicm93c2VyIHdpbmRvdyBiZWluZyBwaHlzaWNhbGx5IHJlc2l6ZWQsIG9yIGZyb20gYSBkZXZpY2VcbiAgICogY2hhbmdpbmcgb3JpZW50YXRpb24uXG4gICAqL1xuICByZXNpemUgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoRE9DVU1FTlQpIHByaXZhdGUgZG9jOiBhbnksIHpvbmU6IE5nWm9uZSkge1xuICAgIHpvbmUucnVuKCgpID0+IHtcbiAgICAgIHRoaXMud2luID0gZG9jLmRlZmF1bHRWaWV3O1xuICAgICAgdGhpcy5iYWNrQnV0dG9uLnN1YnNjcmliZVdpdGhQcmlvcml0eSA9IGZ1bmN0aW9uIChwcmlvcml0eSwgY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3Vic2NyaWJlKChldikgPT4ge1xuICAgICAgICAgIHJldHVybiBldi5yZWdpc3Rlcihwcmlvcml0eSwgKHByb2Nlc3NOZXh0SGFuZGxlcikgPT4gem9uZS5ydW4oKCkgPT4gY2FsbGJhY2socHJvY2Vzc05leHRIYW5kbGVyKSkpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHByb3h5RXZlbnQodGhpcy5wYXVzZSwgZG9jLCAncGF1c2UnLCB6b25lKTtcbiAgICAgIHByb3h5RXZlbnQodGhpcy5yZXN1bWUsIGRvYywgJ3Jlc3VtZScsIHpvbmUpO1xuICAgICAgcHJveHlFdmVudCh0aGlzLmJhY2tCdXR0b24sIGRvYywgJ2lvbkJhY2tCdXR0b24nLCB6b25lKTtcbiAgICAgIHByb3h5RXZlbnQodGhpcy5yZXNpemUsIHRoaXMud2luLCAncmVzaXplJywgem9uZSk7XG4gICAgICBwcm94eUV2ZW50KHRoaXMua2V5Ym9hcmREaWRTaG93LCB0aGlzLndpbiwgJ2lvbktleWJvYXJkRGlkU2hvdycsIHpvbmUpO1xuICAgICAgcHJveHlFdmVudCh0aGlzLmtleWJvYXJkRGlkSGlkZSwgdGhpcy53aW4sICdpb25LZXlib2FyZERpZEhpZGUnLCB6b25lKTtcblxuICAgICAgbGV0IHJlYWR5UmVzb2x2ZTogKHZhbHVlOiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgICB0aGlzLl9yZWFkeVByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzKSA9PiB7XG4gICAgICAgIHJlYWR5UmVzb2x2ZSA9IHJlcztcbiAgICAgIH0pO1xuICAgICAgaWYgKHRoaXMud2luPy5bJ2NvcmRvdmEnXSkge1xuICAgICAgICBkb2MuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAnZGV2aWNlcmVhZHknLFxuICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgIHJlYWR5UmVzb2x2ZSgnY29yZG92YScpO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBvbmNlOiB0cnVlIH1cbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tbm9uLW51bGwtYXNzZXJ0aW9uXG4gICAgICAgIHJlYWR5UmVzb2x2ZSEoJ2RvbScpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHJldHVybnMgdHJ1ZS9mYWxzZSBiYXNlZCBvbiBwbGF0Zm9ybS5cbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIERlcGVuZGluZyBvbiB0aGUgcGxhdGZvcm0gdGhlIHVzZXIgaXMgb24sIGBpcyhwbGF0Zm9ybU5hbWUpYCB3aWxsXG4gICAqIHJldHVybiBgdHJ1ZWAgb3IgYGZhbHNlYC4gTm90ZSB0aGF0IHRoZSBzYW1lIGFwcCBjYW4gcmV0dXJuIGB0cnVlYFxuICAgKiBmb3IgbW9yZSB0aGFuIG9uZSBwbGF0Zm9ybSBuYW1lLiBGb3IgZXhhbXBsZSwgYW4gYXBwIHJ1bm5pbmcgZnJvbVxuICAgKiBhbiBpUGFkIHdvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIHRoZSBwbGF0Zm9ybSBuYW1lczogYG1vYmlsZWAsXG4gICAqIGBpb3NgLCBgaXBhZGAsIGFuZCBgdGFibGV0YC4gQWRkaXRpb25hbGx5LCBpZiB0aGUgYXBwIHdhcyBydW5uaW5nXG4gICAqIGZyb20gQ29yZG92YSB0aGVuIGBjb3Jkb3ZhYCB3b3VsZCBiZSB0cnVlLCBhbmQgaWYgaXQgd2FzIHJ1bm5pbmdcbiAgICogZnJvbSBhIHdlYiBicm93c2VyIG9uIHRoZSBpUGFkIHRoZW4gYG1vYmlsZXdlYmAgd291bGQgYmUgYHRydWVgLlxuICAgKlxuICAgKiBgYGBcbiAgICogaW1wb3J0IHsgUGxhdGZvcm0gfSBmcm9tICdpb25pYy1hbmd1bGFyJztcbiAgICpcbiAgICogQENvbXBvbmVudCh7Li4ufSlcbiAgICogZXhwb3J0IE15UGFnZSB7XG4gICAqICAgY29uc3RydWN0b3IocHVibGljIHBsYXRmb3JtOiBQbGF0Zm9ybSkge1xuICAgKiAgICAgaWYgKHRoaXMucGxhdGZvcm0uaXMoJ2lvcycpKSB7XG4gICAqICAgICAgIC8vIFRoaXMgd2lsbCBvbmx5IHByaW50IHdoZW4gb24gaU9TXG4gICAqICAgICAgIGNvbnNvbGUubG9nKCdJIGFtIGFuIGlPUyBkZXZpY2UhJyk7XG4gICAqICAgICB9XG4gICAqICAgfVxuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiB8IFBsYXRmb3JtIE5hbWUgICB8IERlc2NyaXB0aW9uICAgICAgICAgICAgICAgICAgICAgICAgfFxuICAgKiB8LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfFxuICAgKiB8IGFuZHJvaWQgICAgICAgICB8IG9uIGEgZGV2aWNlIHJ1bm5pbmcgQW5kcm9pZC4gICAgICAgfFxuICAgKiB8IGNhcGFjaXRvciAgICAgICB8IG9uIGEgZGV2aWNlIHJ1bm5pbmcgQ2FwYWNpdG9yLiAgICAgfFxuICAgKiB8IGNvcmRvdmEgICAgICAgICB8IG9uIGEgZGV2aWNlIHJ1bm5pbmcgQ29yZG92YS4gICAgICAgfFxuICAgKiB8IGlvcyAgICAgICAgICAgICB8IG9uIGEgZGV2aWNlIHJ1bm5pbmcgaU9TLiAgICAgICAgICAgfFxuICAgKiB8IGlwYWQgICAgICAgICAgICB8IG9uIGFuIGlQYWQgZGV2aWNlLiAgICAgICAgICAgICAgICAgfFxuICAgKiB8IGlwaG9uZSAgICAgICAgICB8IG9uIGFuIGlQaG9uZSBkZXZpY2UuICAgICAgICAgICAgICAgfFxuICAgKiB8IHBoYWJsZXQgICAgICAgICB8IG9uIGEgcGhhYmxldCBkZXZpY2UuICAgICAgICAgICAgICAgfFxuICAgKiB8IHRhYmxldCAgICAgICAgICB8IG9uIGEgdGFibGV0IGRldmljZS4gICAgICAgICAgICAgICAgfFxuICAgKiB8IGVsZWN0cm9uICAgICAgICB8IGluIEVsZWN0cm9uIG9uIGEgZGVza3RvcCBkZXZpY2UuICAgfFxuICAgKiB8IHB3YSAgICAgICAgICAgICB8IGFzIGEgUFdBIGFwcC4gICAgICAgICAgICAgICAgICAgICAgfFxuICAgKiB8IG1vYmlsZSAgICAgICAgICB8IG9uIGEgbW9iaWxlIGRldmljZS4gICAgICAgICAgICAgICAgfFxuICAgKiB8IG1vYmlsZXdlYiAgICAgICB8IG9uIGEgbW9iaWxlIGRldmljZSBpbiBhIGJyb3dzZXIuICAgfFxuICAgKiB8IGRlc2t0b3AgICAgICAgICB8IG9uIGEgZGVza3RvcCBkZXZpY2UuICAgICAgICAgICAgICAgfFxuICAgKiB8IGh5YnJpZCAgICAgICAgICB8IGlzIGEgY29yZG92YSBvciBjYXBhY2l0b3IgYXBwLiAgICAgfFxuICAgKlxuICAgKi9cbiAgaXMocGxhdGZvcm1OYW1lOiBQbGF0Zm9ybXMpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaXNQbGF0Zm9ybSh0aGlzLndpbiwgcGxhdGZvcm1OYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgcGxhdGZvcm1zXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBEZXBlbmRpbmcgb24gd2hhdCBkZXZpY2UgeW91IGFyZSBvbiwgYHBsYXRmb3Jtc2AgY2FuIHJldHVybiBtdWx0aXBsZSB2YWx1ZXMuXG4gICAqIEVhY2ggcG9zc2libGUgdmFsdWUgaXMgYSBoaWVyYXJjaHkgb2YgcGxhdGZvcm1zLiBGb3IgZXhhbXBsZSwgb24gYW4gaVBob25lLFxuICAgKiBpdCB3b3VsZCByZXR1cm4gYG1vYmlsZWAsIGBpb3NgLCBhbmQgYGlwaG9uZWAuXG4gICAqXG4gICAqIGBgYFxuICAgKiBpbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gJ2lvbmljLWFuZ3VsYXInO1xuICAgKlxuICAgKiBAQ29tcG9uZW50KHsuLi59KVxuICAgKiBleHBvcnQgTXlQYWdlIHtcbiAgICogICBjb25zdHJ1Y3RvcihwdWJsaWMgcGxhdGZvcm06IFBsYXRmb3JtKSB7XG4gICAqICAgICAvLyBUaGlzIHdpbGwgcHJpbnQgYW4gYXJyYXkgb2YgdGhlIGN1cnJlbnQgcGxhdGZvcm1zXG4gICAqICAgICBjb25zb2xlLmxvZyh0aGlzLnBsYXRmb3JtLnBsYXRmb3JtcygpKTtcbiAgICogICB9XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBwbGF0Zm9ybXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBnZXRQbGF0Zm9ybXModGhpcy53aW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBwcm9taXNlIHdoZW4gdGhlIHBsYXRmb3JtIGlzIHJlYWR5IGFuZCBuYXRpdmUgZnVuY3Rpb25hbGl0eVxuICAgKiBjYW4gYmUgY2FsbGVkLiBJZiB0aGUgYXBwIGlzIHJ1bm5pbmcgZnJvbSB3aXRoaW4gYSB3ZWIgYnJvd3NlciwgdGhlblxuICAgKiB0aGUgcHJvbWlzZSB3aWxsIHJlc29sdmUgd2hlbiB0aGUgRE9NIGlzIHJlYWR5LiBXaGVuIHRoZSBhcHAgaXMgcnVubmluZ1xuICAgKiBmcm9tIGFuIGFwcGxpY2F0aW9uIGVuZ2luZSBzdWNoIGFzIENvcmRvdmEsIHRoZW4gdGhlIHByb21pc2Ugd2lsbFxuICAgKiByZXNvbHZlIHdoZW4gQ29yZG92YSB0cmlnZ2VycyB0aGUgYGRldmljZXJlYWR5YCBldmVudC5cbiAgICpcbiAgICogVGhlIHJlc29sdmVkIHZhbHVlIGlzIHRoZSBgcmVhZHlTb3VyY2VgLCB3aGljaCBzdGF0ZXMgd2hpY2ggcGxhdGZvcm1cbiAgICogcmVhZHkgd2FzIHVzZWQuIEZvciBleGFtcGxlLCB3aGVuIENvcmRvdmEgaXMgcmVhZHksIHRoZSByZXNvbHZlZCByZWFkeVxuICAgKiBzb3VyY2UgaXMgYGNvcmRvdmFgLiBUaGUgZGVmYXVsdCByZWFkeSBzb3VyY2UgdmFsdWUgd2lsbCBiZSBgZG9tYC4gVGhlXG4gICAqIGByZWFkeVNvdXJjZWAgaXMgdXNlZnVsIGlmIGRpZmZlcmVudCBsb2dpYyBzaG91bGQgcnVuIGRlcGVuZGluZyBvbiB0aGVcbiAgICogcGxhdGZvcm0gdGhlIGFwcCBpcyBydW5uaW5nIGZyb20uIEZvciBleGFtcGxlLCBvbmx5IENvcmRvdmEgY2FuIGV4ZWN1dGVcbiAgICogdGhlIHN0YXR1cyBiYXIgcGx1Z2luLCBzbyB0aGUgd2ViIHNob3VsZCBub3QgcnVuIHN0YXR1cyBiYXIgcGx1Z2luIGxvZ2ljLlxuICAgKlxuICAgKiBgYGBcbiAgICogaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG4gICAqIGltcG9ydCB7IFBsYXRmb3JtIH0gZnJvbSAnaW9uaWMtYW5ndWxhcic7XG4gICAqXG4gICAqIEBDb21wb25lbnQoey4uLn0pXG4gICAqIGV4cG9ydCBNeUFwcCB7XG4gICAqICAgY29uc3RydWN0b3IocHVibGljIHBsYXRmb3JtOiBQbGF0Zm9ybSkge1xuICAgKiAgICAgdGhpcy5wbGF0Zm9ybS5yZWFkeSgpLnRoZW4oKHJlYWR5U291cmNlKSA9PiB7XG4gICAqICAgICAgIGNvbnNvbGUubG9nKCdQbGF0Zm9ybSByZWFkeSBmcm9tJywgcmVhZHlTb3VyY2UpO1xuICAgKiAgICAgICAvLyBQbGF0Zm9ybSBub3cgcmVhZHksIGV4ZWN1dGUgYW55IHJlcXVpcmVkIG5hdGl2ZSBjb2RlXG4gICAqICAgICB9KTtcbiAgICogICB9XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICByZWFkeSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLl9yZWFkeVByb21pc2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBpZiB0aGlzIGFwcCBpcyB1c2luZyByaWdodC10by1sZWZ0IGxhbmd1YWdlIGRpcmVjdGlvbiBvciBub3QuXG4gICAqIFdlIHJlY29tbWVuZCB0aGUgYXBwJ3MgYGluZGV4Lmh0bWxgIGZpbGUgYWxyZWFkeSBoYXMgdGhlIGNvcnJlY3QgYGRpcmBcbiAgICogYXR0cmlidXRlIHZhbHVlIHNldCwgc3VjaCBhcyBgPGh0bWwgZGlyPVwibHRyXCI+YCBvciBgPGh0bWwgZGlyPVwicnRsXCI+YC5cbiAgICogW1czQzogU3RydWN0dXJhbCBtYXJrdXAgYW5kIHJpZ2h0LXRvLWxlZnQgdGV4dCBpbiBIVE1MXShodHRwOi8vd3d3LnczLm9yZy9JbnRlcm5hdGlvbmFsL3F1ZXN0aW9ucy9xYS1odG1sLWRpcilcbiAgICovXG4gIGdldCBpc1JUTCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5kb2MuZGlyID09PSAncnRsJztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHF1ZXJ5IHN0cmluZyBwYXJhbWV0ZXJcbiAgICovXG4gIGdldFF1ZXJ5UGFyYW0oa2V5OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgICByZXR1cm4gcmVhZFF1ZXJ5UGFyYW0odGhpcy53aW4ubG9jYXRpb24uaHJlZiwga2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYXBwIGlzIGluIGxhbmRzY2FwZSBtb2RlLlxuICAgKi9cbiAgaXNMYW5kc2NhcGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLmlzUG9ydHJhaXQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYXBwIGlzIGluIHBvcnRyYWl0IG1vZGUuXG4gICAqL1xuICBpc1BvcnRyYWl0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLndpbi5tYXRjaE1lZGlhPy4oJyhvcmllbnRhdGlvbjogcG9ydHJhaXQpJykubWF0Y2hlcztcbiAgfVxuXG4gIHRlc3RVc2VyQWdlbnQoZXhwcmVzc2lvbjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgY29uc3QgbmF2ID0gdGhpcy53aW4ubmF2aWdhdG9yO1xuICAgIHJldHVybiAhIShuYXY/LnVzZXJBZ2VudCAmJiBuYXYudXNlckFnZW50LmluZGV4T2YoZXhwcmVzc2lvbikgPj0gMCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjdXJyZW50IHVybC5cbiAgICovXG4gIHVybCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLndpbi5sb2NhdGlvbi5ocmVmO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIHdpZHRoIG9mIHRoZSBwbGF0Zm9ybSdzIHZpZXdwb3J0IHVzaW5nIGB3aW5kb3cuaW5uZXJXaWR0aGAuXG4gICAqL1xuICB3aWR0aCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLndpbi5pbm5lcldpZHRoO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGhlaWdodCBvZiB0aGUgcGxhdGZvcm0ncyB2aWV3cG9ydCB1c2luZyBgd2luZG93LmlubmVySGVpZ2h0YC5cbiAgICovXG4gIGhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLndpbi5pbm5lckhlaWdodDtcbiAgfVxufVxuXG5jb25zdCByZWFkUXVlcnlQYXJhbSA9ICh1cmw6IHN0cmluZywga2V5OiBzdHJpbmcpID0+IHtcbiAga2V5ID0ga2V5LnJlcGxhY2UoL1tbXFxdXFxcXF0vZywgJ1xcXFwkJicpO1xuICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoJ1tcXFxcPyZdJyArIGtleSArICc9KFteJiNdKiknKTtcbiAgY29uc3QgcmVzdWx0cyA9IHJlZ2V4LmV4ZWModXJsKTtcbiAgcmV0dXJuIHJlc3VsdHMgPyBkZWNvZGVVUklDb21wb25lbnQocmVzdWx0c1sxXS5yZXBsYWNlKC9cXCsvZywgJyAnKSkgOiBudWxsO1xufTtcblxuY29uc3QgcHJveHlFdmVudCA9IDxUPihlbWl0dGVyOiBTdWJqZWN0PFQ+LCBlbDogRXZlbnRUYXJnZXQsIGV2ZW50TmFtZTogc3RyaW5nLCB6b25lOiBOZ1pvbmUpID0+IHtcbiAgaWYgKGVsKSB7XG4gICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIChldikgPT4ge1xuICAgICAgLyoqXG4gICAgICAgKiBgem9uZS5ydW5gIGlzIHJlcXVpcmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHdlIGFyZSBydW5uaW5nIGluc2lkZSB0aGUgQW5ndWxhciB6b25lXG4gICAgICAgKiBhdCBhbGwgdGltZXMuIFRoaXMgaXMgbmVjZXNzYXJ5IHNpbmNlIGFuIGFwcCB0aGF0IGhhcyBDYXBhY2l0b3Igd2lsbFxuICAgICAgICogb3ZlcnJpZGUgdGhlIGBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyYCB3aXRoIGl0cyBvd24gaW1wbGVtZW50YXRpb24uXG4gICAgICAgKiBUaGUgb3ZlcnJpZGUgY2F1c2VzIHRoZSBldmVudCB0byBubyBsb25nZXIgYmUgaW4gdGhlIEFuZ3VsYXIgem9uZS5cbiAgICAgICAqL1xuICAgICAgem9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAvLyA/PyBjb3Jkb3ZhIG1pZ2h0IGVtaXQgXCJudWxsXCIgZXZlbnRzXG4gICAgICAgIGNvbnN0IHZhbHVlID0gZXYgIT0gbnVsbCA/IChldiBhcyBhbnkpLmRldGFpbCA6IHVuZGVmaW5lZDtcbiAgICAgICAgZW1pdHRlci5uZXh0KHZhbHVlKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG59O1xuIl19