@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
JavaScript
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