UNPKG

@nota/nativescript-webview-ext

Version:

Extended WebView for NativeScript which adds 'x-local' scheme for local-files. events between WebView and native-layer, javascript execution, injecting CSS and JS-files.

621 lines (619 loc) 77.7 kB
import "@nativescript/core"; import { alert, confirm, File, knownFolders, profile, prompt, Trace } from "@nativescript/core"; import { isEnabledProperty } from "@nativescript/core/ui/core/view"; import { webViewBridge } from "./nativescript-webview-bridge-loader"; import { autoInjectJSBridgeProperty, limitsNavigationsToAppBoundDomainsProperty, scrollBounceProperty, viewPortProperty, WebViewExtBase, } from "./webview-ext-common"; export * from "./webview-ext-common"; const messageHandlerName = "nsBridge"; export class WebViewExt extends WebViewExtBase { constructor() { super(...arguments); this.wkNamedUserScripts = []; this.supportXLocalScheme = typeof CustomUrlSchemeHandler !== "undefined"; this.viewPortSize = { initialScale: 1.0 }; this.limitsNavigationsToAppBoundDomains = false; } createNativeView() { const configuration = WKWebViewConfiguration.new(); configuration.dataDetectorTypes = -1; this.wkWebViewConfiguration = configuration; const messageHandler = WKScriptMessageHandlerNotaImpl.initWithOwner(new WeakRef(this)); const wkUController = (this.wkUserContentController = WKUserContentController.new()); wkUController.addScriptMessageHandlerName(messageHandler, messageHandlerName); configuration.userContentController = wkUController; configuration.preferences.setValueForKey(true, "allowFileAccessFromFileURLs"); configuration.setValueForKey(true, "allowUniversalAccessFromFileURLs"); configuration.limitsNavigationsToAppBoundDomains = this.limitsNavigationsToAppBoundDomains; if (this.supportXLocalScheme) { this.wkCustomUrlSchemeHandler = new CustomUrlSchemeHandler(); configuration.setURLSchemeHandlerForURLScheme(this.wkCustomUrlSchemeHandler, this.interceptScheme); } const webview = new WKWebView({ frame: CGRectZero, configuration, }); return webview; } initNativeView() { super.initNativeView(); this.wkNavigationDelegate = WKNavigationDelegateNotaImpl.initWithOwner(new WeakRef(this)); this.wkUIDelegate = WKUIDelegateNotaImpl.initWithOwner(new WeakRef(this)); this.loadWKUserScripts(); } disposeNativeView() { var _a, _b; (_b = (_a = this.wkWebViewConfiguration) === null || _a === void 0 ? void 0 : _a.userContentController) === null || _b === void 0 ? void 0 : _b.removeScriptMessageHandlerForName(messageHandlerName); this.wkWebViewConfiguration = null; this.wkNavigationDelegate = null; this.wkCustomUrlSchemeHandler = null; this.wkUIDelegate = null; super.disposeNativeView(); } injectWebViewBridge() { return this.ensurePolyfills(); } async injectViewPortMeta() { this.resetViewPortCode(); if (this.supportXLocalScheme) { return; } return await super.injectViewPortMeta(); } async executeJavaScript(scriptCode, stringifyResult = true) { if (stringifyResult) { scriptCode = ` (function(window) { var result = null; try { result = ${scriptCode.trim()}; } catch (err) { return JSON.stringify({ error: true, message: err.message, stack: err.stack }); } try { return JSON.stringify(result); } catch (err) { return result; } })(window); `; } const nativeView = this.nativeViewProtected; if (!nativeView) { return Promise.reject(new Error("WebView is missing")); } const rawResult = await new Promise((resolve, reject) => { nativeView.evaluateJavaScriptCompletionHandler(scriptCode.trim(), (result, error) => { if (error) { reject(error); return; } resolve(result); }); }); const result = await this.parseWebViewJavascriptResult(rawResult); const r = result; if (r && typeof r === "object" && r.error) { const error = new Error(r.message); error.webStack = r.stack; throw error; } return result; } onLoaded() { super.onLoaded(); const nativeView = this.nativeViewProtected; if (nativeView) { nativeView.navigationDelegate = this.wkNavigationDelegate; nativeView.UIDelegate = this.wkUIDelegate; } } onUnloaded() { const nativeView = this.nativeViewProtected; if (nativeView) { nativeView.navigationDelegate = null; nativeView.UIDelegate = null; } super.onUnloaded(); } stopLoading() { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.stopLoading(); } _loadUrl(src) { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } const nsURL = NSURL.URLWithString(src); if (src.startsWith("file:///")) { const cachePath = src.substring(0, src.lastIndexOf("/")); const nsReadAccessUrl = NSURL.URLWithString(cachePath); this.writeTrace(`WKWebViewWrapper.loadUrl("${src}") -> ios.loadFileURLAllowingReadAccessToURL("${nsURL}", "${nsReadAccessUrl}"`); nativeView.loadFileURLAllowingReadAccessToURL(nsURL, nsReadAccessUrl); } else { const nsRequestWithUrl = NSURLRequest.requestWithURL(nsURL); this.writeTrace(`WKWebViewWrapper.loadUrl("${src}") -> ios.loadRequest("${nsRequestWithUrl}"`); nativeView.loadRequest(nsRequestWithUrl); } } _loadData(content) { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } const baseUrl = `file:///${knownFolders.currentApp().path}/`; const nsBaseUrl = NSURL.URLWithString(baseUrl); this.writeTrace(`WKWebViewWrapper.loadUrl(content) -> this.ios.loadHTMLStringBaseURL("${nsBaseUrl}")`); nativeView.loadHTMLStringBaseURL(content, nsBaseUrl); } get canGoBack() { const nativeView = this.nativeViewProtected; return nativeView && !!nativeView.canGoBack; } get canGoForward() { const nativeView = this.nativeViewProtected; return nativeView && !!nativeView.canGoForward; } goBack() { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.goBack(); } goForward() { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.goForward(); } reload() { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.reload(); } _webAlert(message, callback) { if (!super._webAlert(message, callback)) { alert(message) .then(() => callback()) .catch(() => callback()); } return true; } _webConfirm(message, callback) { if (!super._webConfirm(message, callback)) { confirm(message) .then((res) => callback(res)) .catch(() => callback(null)); } return true; } _webPrompt(message, defaultText, callback) { if (!super._webPrompt(message, defaultText, callback)) { prompt(message, defaultText) .then((res) => { if (res.result) { callback(res.text); } else { callback(null); } }) .catch(() => callback(null)); } return true; } registerLocalResource(resourceName, path) { const cls = `WebViewExt<${this}.ios>.registerLocalResource("${resourceName}", "${path}")`; if (!this.supportXLocalScheme) { this.writeTrace(`${cls} -> custom schema isn't support on iOS <11`, Trace.messageType.error); return; } resourceName = this.fixLocalResourceName(resourceName); const filepath = this.resolveLocalResourceFilePath(path); if (!filepath) { this.writeTrace(`${cls} -> file doesn't exist`, Trace.messageType.error); return; } this.writeTrace(`${cls} -> file: "${filepath}"`); this.registerLocalResourceForNative(resourceName, filepath); } unregisterLocalResource(resourceName) { const cls = `WebViewExt<${this}.ios>.unregisterLocalResource("${resourceName}")`; if (!this.supportXLocalScheme) { this.writeTrace(`${cls} -> custom schema isn't support on iOS <11`, Trace.messageType.error); return; } this.writeTrace(cls); resourceName = this.fixLocalResourceName(resourceName); this.unregisterLocalResourceForNative(resourceName); } getRegisteredLocalResource(resourceName) { resourceName = this.fixLocalResourceName(resourceName); const cls = `WebViewExt<${this}.ios>.getRegisteredLocalResource("${resourceName}")`; if (!this.supportXLocalScheme) { this.writeTrace(`${cls} -> custom schema isn't support on iOS <11`, Trace.messageType.error); return; } let result = this.getRegisteredLocalResourceFromNative(resourceName); this.writeTrace(`${cls} -> "${result}"`); return result; } getTitle() { return this.executeJavaScript("document.title"); } async autoLoadStyleSheetFile(resourceName, path, insertBefore) { const filepath = this.resolveLocalResourceFilePath(path); if (!filepath) { this.writeTrace(`WKWebViewWrapper.autoLoadStyleSheetFile("${resourceName}", "${path}") - couldn't resolve filepath`); return; } resourceName = this.fixLocalResourceName(resourceName); const scriptCode = await this.generateLoadCSSFileScriptCode(resourceName, filepath, insertBefore); if (scriptCode) { this.addNamedWKUserScript(`auto-load-css-${resourceName}`, scriptCode); } } removeAutoLoadStyleSheetFile(resourceName) { resourceName = this.fixLocalResourceName(resourceName); this.removeNamedWKUserScript(`auto-load-css-${resourceName}`); } async autoLoadJavaScriptFile(resourceName, path) { const filepath = this.resolveLocalResourceFilePath(path); if (!filepath) { this.writeTrace(`WKWebViewWrapper.autoLoadJavaScriptFile("${resourceName}", "${path}") - couldn't resolve filepath`); return; } const scriptCode = await File.fromPath(filepath).readText(); this.addNamedWKUserScript(resourceName, scriptCode); } removeAutoLoadJavaScriptFile(resourceName) { const fixedResourceName = this.fixLocalResourceName(resourceName); const href = `${this.interceptScheme}://${fixedResourceName}`; this.removeNamedWKUserScript(href); } [autoInjectJSBridgeProperty.setNative](enabled) { this.loadWKUserScripts(enabled); } [scrollBounceProperty.getDefault]() { const nativeView = this.nativeViewProtected; if (!nativeView) { return false; } return nativeView.scrollView.bounces; } [scrollBounceProperty.setNative](enabled) { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.scrollView.bounces = !!enabled; } [viewPortProperty.setNative](value) { if (this.src) { this.injectViewPortMeta(); } } [limitsNavigationsToAppBoundDomainsProperty.setNative](enabled) { this.limitsNavigationsToAppBoundDomains = enabled; } [limitsNavigationsToAppBoundDomainsProperty.getDefault]() { return false; } [isEnabledProperty.setNative](enabled) { const nativeView = this.nativeViewProtected; if (!nativeView) { return; } nativeView.userInteractionEnabled = !!enabled; nativeView.scrollView.userInteractionEnabled = !!enabled; } loadWKUserScripts(autoInjectJSBridge = this.autoInjectJSBridge) { if (!this.wkUserScriptViewPortCode) { this.wkUserScriptViewPortCode = this.makeWKUserScriptPromise(this.generateViewPortCode()); } this.wkUserContentController.removeAllUserScripts(); this.addUserScriptFromPromise(this.wkUserScriptViewPortCode); if (!autoInjectJSBridge) { return; } if (!this.wkUserScriptInjectWebViewBridge) { this.wkUserScriptInjectWebViewBridge = this.createWkUserScript(webViewBridge); } this.addUserScript(this.wkUserScriptInjectWebViewBridge); for (const { wkUserScript } of this.wkNamedUserScripts) { this.addUserScript(wkUserScript); } } removeNamedWKUserScript(resourceName) { const idx = this.wkNamedUserScripts.findIndex((val) => val.resourceName === resourceName); if (idx === -1) { return; } this.wkNamedUserScripts.splice(idx, 1); this.loadWKUserScripts(); } async resetViewPortCode() { this.wkUserScriptViewPortCode = null; const viewPortScriptCode = await this.generateViewPortCode(); if (viewPortScriptCode) { this.executeJavaScript(viewPortScriptCode); this.loadWKUserScripts(); } } registerLocalResourceForNative(resourceName, filepath) { if (!this.wkCustomUrlSchemeHandler) { return; } this.wkCustomUrlSchemeHandler.registerLocalResourceForKeyFilepath(resourceName, filepath); } unregisterLocalResourceForNative(resourceName) { if (!this.wkCustomUrlSchemeHandler) { return; } this.wkCustomUrlSchemeHandler.unregisterLocalResourceForKey(resourceName); } getRegisteredLocalResourceFromNative(resourceName) { if (!this.wkCustomUrlSchemeHandler) { return; } return this.wkCustomUrlSchemeHandler.getRegisteredLocalResourceForKey(resourceName); } async makeWKUserScriptPromise(scriptCodePromise) { const scriptCode = await scriptCodePromise; if (!scriptCode) { return null; } return this.createWkUserScript(scriptCode); } async addUserScriptFromPromise(userScriptPromise) { const userScript = await userScriptPromise; if (!userScript) { return; } return this.addUserScript(userScript); } addUserScript(userScript) { if (!userScript) { return; } this.wkUserContentController.addUserScript(userScript); } addNamedWKUserScript(resourceName, scriptCode) { if (!scriptCode) { return; } this.removeNamedWKUserScript(resourceName); const wkUserScript = this.createWkUserScript(scriptCode); this.wkNamedUserScripts.push({ resourceName, wkUserScript }); this.addUserScript(wkUserScript); } createWkUserScript(source) { return WKUserScript.alloc().initWithSourceInjectionTimeForMainFrameOnly(source, 1, true); } } WebViewExt.supportXLocalScheme = typeof CustomUrlSchemeHandler !== "undefined"; __decorate([ profile, __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], WebViewExt.prototype, "onLoaded", null); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WKNavigationDelegateNotaImpl = void 0; var WKNavigationDelegateNotaImpl = /** @class */ (function (_super) { __extends(WKNavigationDelegateNotaImpl, _super); function WKNavigationDelegateNotaImpl() { return _super !== null && _super.apply(this, arguments) || this; } WKNavigationDelegateNotaImpl.initWithOwner = function (owner) { var handler = WKNavigationDelegateNotaImpl.new(); handler.owner = owner; return handler; }; WKNavigationDelegateNotaImpl.prototype.webViewDecidePolicyForNavigationActionDecisionHandler = function (webView, navigationAction, decisionHandler) { var owner = this.owner.get(); if (!owner) { decisionHandler(WKNavigationActionPolicy.Cancel); return; } var request = navigationAction.request; var httpMethod = request.HTTPMethod; var url = request.URL && request.URL.absoluteString; owner.writeTrace("webViewDecidePolicyForNavigationActionDecisionHandler: \"" + url + "\""); if (!url) { return; } var navType = "other"; switch (navigationAction.navigationType) { case WKNavigationType.LinkActivated: { navType = "linkClicked"; break; } case WKNavigationType.FormSubmitted: { navType = "formSubmitted"; break; } case WKNavigationType.BackForward: { navType = "backForward"; break; } case WKNavigationType.Reload: { navType = "reload"; break; } case WKNavigationType.FormResubmitted: { navType = "formResubmitted"; break; } default: { navType = "other"; break; } } var shouldOverrideUrlLoading = owner._onShouldOverrideUrlLoading(url, httpMethod, navType); if (shouldOverrideUrlLoading === true) { owner.writeTrace("WKNavigationDelegateClass.webViewDecidePolicyForNavigationActionDecisionHandler(\"" + url + "\", \"" + navigationAction.navigationType + "\") -> method:" + httpMethod + " \"" + navType + "\" -> cancel"); decisionHandler(WKNavigationActionPolicy.Cancel); return; } decisionHandler(WKNavigationActionPolicy.Allow); owner.writeTrace("WKNavigationDelegateClass.webViewDecidePolicyForNavigationActionDecisionHandler(\"" + url + "\", \"" + navigationAction.navigationType + "\") -> method:" + httpMethod + " \"" + navType + "\""); owner._onLoadStarted(url, navType); }; WKNavigationDelegateNotaImpl.prototype.webViewDidStartProvisionalNavigation = function (webView, navigation) { var owner = this.owner.get(); if (!owner) { return; } owner.writeTrace("WKNavigationDelegateClass.webViewDidStartProvisionalNavigation(\"" + webView.URL + "\")"); }; WKNavigationDelegateNotaImpl.prototype.webViewDidFinishNavigation = function (webView, navigation) { var owner = this.owner.get(); if (!owner) { return; } owner.writeTrace("WKNavigationDelegateClass.webViewDidFinishNavigation(\"" + webView.URL + "\")"); var src = owner.src; if (webView.URL) { src = webView.URL.absoluteString; } owner._onLoadFinished(src).catch(function () { return void 0; }); }; WKNavigationDelegateNotaImpl.prototype.webViewDidFailNavigationWithError = function (webView, navigation, error) { var owner = this.owner.get(); if (!owner) { return; } var src = owner.src; if (webView.URL) { src = webView.URL.absoluteString; } owner.writeTrace("WKNavigationDelegateClass.webViewDidFailNavigationWithError(\"" + error.localizedDescription + "\")"); owner._onLoadFinished(src, error.localizedDescription).catch(function () { return void 0; }); }; WKNavigationDelegateNotaImpl.prototype.webViewDidFailProvisionalNavigationWithError = function (webView, navigation, error) { var owner = this.owner.get(); if (!owner) { return; } var src = owner.src; if (webView.URL && webView.URL.absoluteString) { src = webView.URL.absoluteString; } owner.writeTrace("WKNavigationDelegateClass.webViewDidFailProvisionalNavigationWithError(" + error.localizedDescription); owner._onLoadFinished(src, error.localizedDescription).catch(function () { return void 0; }); }; WKNavigationDelegateNotaImpl.ObjCProtocols = [WKNavigationDelegate]; return WKNavigationDelegateNotaImpl; }(NSObject)); exports.WKNavigationDelegateNotaImpl = WKNavigationDelegateNotaImpl; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WKScriptMessageHandlerNotaImpl = void 0; var WKScriptMessageHandlerNotaImpl = /** @class */ (function (_super) { __extends(WKScriptMessageHandlerNotaImpl, _super); function WKScriptMessageHandlerNotaImpl() { return _super !== null && _super.apply(this, arguments) || this; } WKScriptMessageHandlerNotaImpl.initWithOwner = function (owner) { var delegate = WKScriptMessageHandlerNotaImpl.new(); delegate.owner = owner; return delegate; }; WKScriptMessageHandlerNotaImpl.prototype.userContentControllerDidReceiveScriptMessage = function (userContentController, webViewMessage) { var owner = this.owner.get(); if (!owner) { return; } try { var message = JSON.parse(webViewMessage.body); owner.onWebViewEvent(message.eventName, message.data); } catch (err) { owner.writeTrace("userContentControllerDidReceiveScriptMessage(" + userContentController + ", " + webViewMessage + ") - bad message: " + JSON.stringify(webViewMessage.body), Trace.messageType.error); } }; WKScriptMessageHandlerNotaImpl.ObjCProtocols = [WKScriptMessageHandler]; return WKScriptMessageHandlerNotaImpl; }(NSObject)); exports.WKScriptMessageHandlerNotaImpl = WKScriptMessageHandlerNotaImpl; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WKUIDelegateNotaImpl = void 0; var WKUIDelegateNotaImpl = /** @class */ (function (_super) { __extends(WKUIDelegateNotaImpl, _super); function WKUIDelegateNotaImpl() { return _super !== null && _super.apply(this, arguments) || this; } WKUIDelegateNotaImpl.initWithOwner = function (owner) { var delegate = WKUIDelegateNotaImpl.new(); delegate.owner = owner; console.log(delegate); return delegate; }; /** * Handle alerts from the webview */ WKUIDelegateNotaImpl.prototype.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = function (webView, message, frame, completionHandler) { var owner = this.owner.get(); if (!owner) { return; } var gotResponse = false; owner._webAlert(message, function () { if (!gotResponse) { completionHandler(); } gotResponse = true; }); }; /** * Handle confirm dialogs from the webview */ WKUIDelegateNotaImpl.prototype.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = function (webView, message, frame, completionHandler) { var owner = this.owner.get(); if (!owner) { return; } var gotResponse = false; owner._webConfirm(message, function (confirmed) { if (!gotResponse) { completionHandler(confirmed); } gotResponse = true; }); }; /** * Handle prompt dialogs from the webview */ WKUIDelegateNotaImpl.prototype.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = function (webView, message, defaultText, frame, completionHandler) { var owner = this.owner.get(); if (!owner) { return; } var gotResponse = false; owner._webPrompt(message, defaultText, function (response) { if (!gotResponse) { completionHandler(response); } gotResponse = true; }); }; WKUIDelegateNotaImpl.ObjCProtocols = [WKUIDelegate]; return WKUIDelegateNotaImpl; }(NSObject)); exports.WKUIDelegateNotaImpl = WKUIDelegateNotaImpl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vidmlldy1leHQuaW9zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsid2Vidmlldy1leHQuaW9zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUNyRSxPQUFPLEVBQ0gsMEJBQTBCLEVBQzFCLDBDQUEwQyxFQUUxQyxvQkFBb0IsRUFFcEIsZ0JBQWdCLEVBQ2hCLGNBQWMsR0FDakIsTUFBTSxzQkFBc0IsQ0FBQztBQUU5QixjQUFjLHNCQUFzQixDQUFDO0FBRXJDLE1BQU0sa0JBQWtCLEdBQUcsVUFBVSxDQUFDO0FBRXRDLE1BQU0sT0FBTyxVQUFXLFNBQVEsY0FBYztJQUE5Qzs7UUFZYyx1QkFBa0IsR0FBRyxFQUc3QixDQUFDO1FBRWEsd0JBQW1CLEdBQUcsT0FBTyxzQkFBc0IsS0FBSyxXQUFXLENBQUM7UUFFN0UsaUJBQVksR0FBRyxFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUNwQyx1Q0FBa0MsR0FBRyxLQUFLLENBQUM7SUE4Z0J2RCxDQUFDO0lBNWdCVSxnQkFBZ0I7UUFDbkIsTUFBTSxhQUFhLEdBQUcsc0JBQXNCLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDbkQsYUFBYSxDQUFDLGlCQUFpQixLQUEwQixDQUFDO1FBQzFELElBQUksQ0FBQyxzQkFBc0IsR0FBRyxhQUFhLENBQUM7UUFFNUMsTUFBTSxjQUFjLEdBQUcsOEJBQThCLENBQUMsYUFBYSxDQUFDLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdkYsTUFBTSxh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QixDQUFDO1FBQzNDLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDYixPQUFPO1NBQ1Y7UUFFRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVTLGFBQWEsQ0FBQyxVQUErQjtRQUNuRCxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2IsT0FBTztTQUNWO1FBRUQsSUFBSSxDQUFDLHVCQUF1QixDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBUVMsb0JBQW9CLENBQUMsWUFBb0IsRUFBRSxVQUFrQjtRQUNuRSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2IsT0FBTztTQUNWO1FBRUQsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRTNDLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUV6RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7UUFFN0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBT1Msa0JBQWtCLENBQUMsTUFBYztRQUN2QyxPQUFPLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQywyQ0FBMkMsQ0FBQyxNQUFNLEtBQTJDLElBQUksQ0FBQyxDQUFDO0lBQ25JLENBQUM7O0FBOWhCYSw4QkFBbUIsR0FBRyxPQUFPLHNCQUFzQixLQUFLLFdBQVcsQ0FBQztBQW1JbEY7SUFEQyxPQUFPOzs7OzBDQVNQIiwic291cmNlc0NvbnRlbnQiOlsiLy8vIDxyZWZlcmVuY2UgcGF0aD1cIi4vdHlwZXMvaW9zL05vdGFXZWJWaWV3RXh0LmQudHNcIiAvPlxuXG5pbXBvcnQgXCJAbmF0aXZlc2NyaXB0L2NvcmVcIjtcbmltcG9ydCB7IGFsZXJ0LCBjb25maXJtLCBGaWxlLCBrbm93bkZvbGRlcnMsIHByb2ZpbGUsIHByb21wdCwgVHJhY2UgfSBmcm9tIFwiQG5hdGl2ZXNjcmlwdC9jb3JlXCI7XG5pbXBvcnQgeyBpc0VuYWJsZWRQcm9wZXJ0eSB9IGZyb20gXCJAbmF0aXZlc2NyaXB0L2NvcmUvdWkvY29yZS92aWV3XCI7XG5pbXBvcnQgeyB3ZWJWaWV3QnJpZGdlIH0gZnJvbSBcIi4vbmF0aXZlc2NyaXB0LXdlYnZpZXctYnJpZGdlLWxvYWRlclwiO1xuaW1wb3J0IHtcbiAgICBhdXRvSW5qZWN0SlNCcmlkZ2VQcm9wZXJ0eSxcbiAgICBsaW1pdHNOYXZpZ2F0aW9uc1RvQXBwQm91bmREb21haW5zUHJvcGVydHksXG4gICAgTmF2aWdhdGlvblR5cGUsXG4gICAgc2Nyb2xsQm91bmNlUHJvcGVydHksXG4gICAgVmlld1BvcnRQcm9wZXJ0aWVzLFxuICAgIHZpZXdQb3J0UHJvcGVydHksXG4gICAgV2ViVmlld0V4dEJhc2UsXG59IGZyb20gXCIuL3dlYnZpZXctZXh0LWNvbW1vblwiO1xuXG5leHBvcnQgKiBmcm9tIFwiLi93ZWJ2aWV3LWV4dC1jb21tb25cIjtcblxuY29uc3QgbWVzc2FnZUhhbmRsZXJOYW1lID0gXCJuc0JyaWRnZVwiO1xuXG5leHBvcnQgY2xhc3MgV2ViVmlld0V4dCBleHRlbmRzIFdlYlZpZXdFeHRCYXNlIHtcbiAgICBwdWJsaWMgaW9zOiBXS1dlYlZpZXc7XG5cbiAgICBwdWJsaWMgc3RhdGljIHN1cHBvcnRYTG9jYWxTY2hlbWUgPSB0eXBlb2YgQ3VzdG9tVXJsU2NoZW1lSGFuZGxlciAhPT0gXCJ1bmRlZmluZWRcIjtcblxuICAgIHByb3RlY3RlZCB3a1dlYlZpZXdDb25maWd1cmF0aW9uOiBXS1dlYlZpZXdDb25maWd1cmF0aW9uO1xuICAgIHByb3RlY3RlZCB3a05hdmlnYXRpb25EZWxlZ2F0ZTogV0tOYXZpZ2F0aW9uRGVsZWdhdGVOb3RhSW1wbDtcbiAgICBwcm90ZWN0ZWQgd2tVSURlbGVnYXRlOiBXS1VJRGVsZWdhdGVOb3RhSW1wbDtcbiAgICBwcm90ZWN0ZWQgd2tDdXN0b21VcmxTY2hlbWVIYW5kbGVyOiBDdXN0b21VcmxTY2hlbWVIYW5kbGVyIHwgdm9pZDtcbiAgICBwcm90ZWN0ZWQgd2tVc2VyQ29udGVudENvbnRyb2xsZXI6IFdLVXNlckNvbnRlbnRDb250cm9sbGVyO1xuICAgIHByb3RlY3RlZCB3a1VzZXJTY3JpcHRJbmplY3RXZWJWaWV3QnJpZGdlPzogV0tVc2VyU2NyaXB0O1xuICAgIHByb3RlY3RlZCB3a1VzZXJTY3JpcHRWaWV3UG9ydENvZGU6IFByb21pc2U8V0tVc2VyU2NyaXB0IHwgbnVsbD4gfCBudWxsO1xuICAgIHByb3RlY3RlZCB3a05hbWVkVXNlclNjcmlwdHMgPSBbXSBhcyBBcnJheTx7XG4gICAgICAgIHJlc291cmNlTmFtZTogc3RyaW5nO1xuICAgICAgICB3a1VzZXJTY3JpcHQ6IFdLVXNlclNjcmlwdDtcbiAgICB9PjtcblxuICAgIHB1YmxpYyByZWFkb25seSBzdXBwb3J0WExvY2FsU2NoZW1lID0gdHlwZW9mIEN1c3RvbVVybFNjaGVtZUhhbmRsZXIgIT09IFwidW5kZWZpbmVkXCI7XG5cbiAgICBwdWJsaWMgdmlld1BvcnRTaXplID0geyBpbml0aWFsU2NhbGU6IDEuMCB9O1xuICAgIHByaXZhdGUgbGltaXRzTmF2aWdhdGlvbnNUb0FwcEJvdW5kRG9tYWlucyA9IGZhbHNlO1xuXG4gICAgcHVibGljIGNyZWF0ZU5hdGl2ZVZpZXcoKSB7XG4gICAgICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSBXS1dlYlZpZXdDb25maWd1cmF0aW9uLm5ldygpO1xuICAgICAgICBjb25maWd1cmF0aW9uLmRhdGFEZXRlY3RvclR5cGVzID0gV0tEYXRhRGV0ZWN0b3JUeXBlcy5BbGw7XG4gICAgICAgIHRoaXMud2tXZWJWaWV3Q29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb247XG5cbiAgICAgICAgY29uc3QgbWVzc2FnZUhhbmRsZXIgPSBXS1NjcmlwdE1lc3NhZ2VIYW5kbGVyTm90YUltcGwuaW5pdFdpdGhPd25lcihuZXcgV2Vha1JlZih0aGlzKSk7XG4gICAgICAgIGNvbnN0IHdrVUNvbnRyb2xsZXIgPSAodGhpcy53a1VzZXJDb250ZW50Q29udHJvbGxlciA9IFdLVXNlckNvbnRlbnRDb250cm9sbGVyLm5ldygpKTtcbiAgICAgICAgd2tVQ29udHJvbGxlci5hZGRTY3JpcHRNZXNzYWdlSGFuZGxlck5hbWUobWVzc2FnZUhhbmRsZXIsIG1lc3NhZ2VIYW5kbGVyTmFtZSk7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24udXNlckNvbnRlbnRDb250cm9sbGVyID0gd2tVQ29udHJvbGxlcjtcbiAgICAgICAgY29uZmlndXJhdGlvbi5wcmVmZXJlbmNlcy5zZXRWYWx1ZUZvcktleSh0cnVlLCBcImFsbG93RmlsZUFjY2Vzc0Zyb21GaWxlVVJMc1wiKTtcbiAgICAgICAgY29uZmlndXJhdGlvbi5zZXRWYWx1ZUZvcktleSh0cnVlLCBcImFsbG93VW5pdmVyc2FsQWNjZXNzRnJvbUZpbGVVUkxzXCIpO1xuICAgICAgICBjb25maWd1cmF0aW9uLmxpbWl0c05hdmlnYXRpb25zVG9BcHBCb3VuZERvbWFpbnMgPSB0aGlzLmxpbWl0c05hdmlnYXRpb25zVG9BcHBCb3VuZERvbWFpbnM7XG4gICAgICAgIGlmICh0aGlzLnN1cHBvcnRYTG9jYWxTY2hlbWUpIHtcbiAgICAgICAgICAgIHRoaXMud2tDdXN0b21VcmxTY2hlbWVIYW5kbGVyID0gbmV3IEN1c3RvbVVybFNjaGVtZUhhbmRsZXIoKTtcbiAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24uc2V0VVJMU2NoZW1lSGFuZGxlckZvclVSTFNjaGVtZSh0aGlzLndrQ3VzdG9tVXJsU2NoZW1lSGFuZGxlciwgdGhpcy5pbnRlcmNlcHRTY2hlbWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd2VidmlldyA9IG5ldyBXS1dlYlZpZXcoe1xuICAgICAgICAgICAgZnJhbWU6IENHUmVjdFplcm8sXG4gICAgICAgICAgICBjb25maWd1cmF0aW9uLFxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gd2VidmlldztcbiAgICB9XG5cbiAgICBwdWJsaWMgaW5pdE5hdGl2ZVZpZXcoKSB7XG4gICAgICAgIHN1cGVyLmluaXROYXRpdmVWaWV3KCk7XG5cbiAgICAgICAgdGhpcy53a05hdmlnYXRpb25EZWxlZ2F0ZSA9IFdLTmF2aWdhdGlvbkRlbGVnYXRlTm90YUltcGwuaW5pdFdpdGhPd25lcihuZXcgV2Vha1JlZih0aGlzKSk7XG4gICAgICAgIHRoaXMud2tVSURlbGVnYXRlID0gV0tVSURlbGVnYXRlTm90YUltcGwuaW5pdFdpdGhPd25lcihuZXcgV2Vha1JlZih0aGlzKSk7XG5cbiAgICAgICAgdGhpcy5sb2FkV0tVc2VyU2NyaXB0cygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBkaXNwb3NlTmF0aXZlVmlldygpIHtcbiAgICAgICAgdGhpcy53a1dlYlZpZXdDb25maWd1cmF0aW9uPy51c2VyQ29udGVudENvbnRyb2xsZXI/LnJlbW92ZVNjcmlwdE1lc3NhZ2VIYW5kbGVyRm9yTmFtZShtZXNzYWdlSGFuZGxlck5hbWUpO1xuICAgICAgICB0aGlzLndrV2ViVmlld0NvbmZpZ3VyYXRpb24gPSBudWxsITtcbiAgICAgICAgdGhpcy53a05hdmlnYXRpb25EZWxlZ2F0ZSA9IG51bGwhO1xuICAgICAgICB0aGlzLndrQ3VzdG9tVXJsU2NoZW1lSGFuZGxlciA9IG51bGwhO1xuICAgICAgICB0aGlzLndrVUlEZWxlZ2F0ZSA9IG51bGwhO1xuXG4gICAgICAgIHN1cGVyLmRpc3Bvc2VOYXRpdmVWaWV3KCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGluamVjdFdlYlZpZXdCcmlkZ2UoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVuc3VyZVBvbHlmaWxscygpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBpbmplY3RWaWV3UG9ydE1ldGEoKSB7XG4gICAgICAgIHRoaXMucmVzZXRWaWV3UG9ydENvZGUoKTtcbiAgICAgICAgaWYgKHRoaXMuc3VwcG9ydFhMb2NhbFNjaGVtZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHN1cGVyLmluamVjdFZpZXdQb3J0TWV0YSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBleGVjdXRlSmF2YVNjcmlwdDxUPihzY3JpcHRDb2RlOiBzdHJpbmcsIHN0cmluZ2lmeVJlc3VsdCA9IHRydWUpOiBQcm9taXNlPFQ+IHtcbiAgICAgICAgaWYgKHN0cmluZ2lmeVJlc3VsdCkge1xuICAgICAgICAgICAgc2NyaXB0Q29kZSA9IGBcbiAgICAgICAgICAgICAgICAoZnVuY3Rpb24od2luZG93KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSBudWxsO1xuXG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSAke3NjcmlwdENvZGUudHJpbSgpfTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YWNrOiBlcnIuc3RhY2tcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShyZXN1bHQpO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KSh3aW5kb3cpO1xuICAgICAgICAgICAgYDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5hdGl2ZVZpZXcgPSB0aGlzLm5hdGl2ZVZpZXdQcm90ZWN0ZWQ7XG4gICAgICAgIGlmICghbmF0aXZlVmlldykge1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIldlYlZpZXcgaXMgbWlzc2luZ1wiKSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByYXdSZXN1bHQgPSBhd2FpdCBuZXcgUHJvbWlzZTxhbnk+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIG5hdGl2ZVZpZXcuZXZhbHVhdGVKYXZhU2NyaXB0Q29tcGxldGlvbkhhbmRsZXIoc2NyaXB0Q29kZS50cmltKCksIChyZXN1bHQsIGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCByZXN1bHQ6IFQgPSBhd2FpdCB0aGlzLnBhcnNlV2ViVmlld0phdmFzY3JpcHRSZXN1bHQocmF3UmVzdWx0KTtcblxuICAgICAgICBjb25zdCByID0gcmVzdWx0IGFzIGFueTtcbiAgICAgICAgaWYgKHIgJiYgdHlwZW9mIHIgPT09IFwib2JqZWN0XCIgJiYgci5lcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3Ioci5tZXNzYWdlKTtcbiAgICAgICAgICAgIChlcnJvciBhcyBhbnkpLndlYlN0YWNrID0gci5zdGFjaztcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBAcHJvZmlsZVxuICAgIHB1YmxpYyBvbkxvYWRlZCgpIHtcbiAgICAgICAgc3VwZXIub25Mb2FkZWQoKTtcblxuICAgICAgICBjb25zdCBuYXRpdmVWaWV3ID0gdGhpcy5uYXRpdmVWaWV3UHJvdGVjdGVkO1xuICAgICAgICBpZiAobmF0aXZlVmlldykge1xuICAgICAgICAgICAgbmF0aXZlVmlldy5uYXZpZ2F0aW9uRGVsZWdhdGUgPSB0aGlzLndrTmF2aWdhdGlvbkRlbGVnYXRlO1xuICAgICAgICAgICAgbmF0aXZlVmlldy5VSURlbGVnYXRlID0gdGhpcy53a1VJRGVsZWdhdGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgb25VbmxvYWRlZCgpIHtcbiAgICAgICAgY29uc3QgbmF0aXZlVmlldyA9IHRoaXMubmF0aXZlVmlld1Byb3RlY3RlZDtcbiAgICAgICAgaWYgKG5hdGl2ZVZpZXcpIHtcbiAgICAgICAgICAgIG5hdGl2ZVZpZXcubmF2aWdhdGlvbkRlbGVnYXRlID0gbnVsbCE7XG4gICAgICAgICAgICBuYXRpdmVWaWV3LlVJRGVsZWdhdGUgPSBudWxsITtcbiAgICAgICAgfVxuXG4gICAgICAgIHN1cGVyLm9uVW5sb2FkZWQoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RvcExvYWRpbmcoKSB7XG4gICAgICAgIGNvbnN0IG5hdGl2ZVZpZXcgPSB0aGlzLm5hdGl2ZVZpZXdQcm90ZWN0ZWQ7XG4gICAgICAgIGlmICghbmF0aXZlVmlldykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbmF0aXZlVmlldy5zdG9wTG9hZGluZygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBfbG9hZFVybChzcmM6IHN0cmluZykge1xuICAgICAgICBjb25zdCBuYXRpdmVWaWV3ID0gdGhpcy5uYXRpdmVWaWV3UHJvdGVjd