matrix-react-sdk
Version:
SDK for matrix.org using React
239 lines (229 loc) • 34.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _matrix = require("matrix-js-sdk/src/matrix");
var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore"));
var _Terms = require("./Terms");
var _MatrixClientPeg = require("./MatrixClientPeg");
var _SdkConfig = _interopRequireDefault(require("./SdkConfig"));
var _UrlUtils = require("./utils/UrlUtils");
/*
Copyright 2024 New Vector Ltd.
Copyright 2016-2019 , 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
// The version of the integration manager API we're intending to work with
const imApiVersion = "1.1";
// TODO: Generify the name of this class and all components within - it's not just for Scalar.
class ScalarAuthClient {
constructor(apiUrl, uiUrl) {
(0, _defineProperty2.default)(this, "scalarToken", void 0);
(0, _defineProperty2.default)(this, "termsInteractionCallback", void 0);
(0, _defineProperty2.default)(this, "isDefaultManager", void 0);
this.apiUrl = apiUrl;
this.uiUrl = uiUrl;
this.scalarToken = null;
// `undefined` to allow `startTermsFlow` to fallback to a default
// callback if this is unset.
this.termsInteractionCallback = undefined;
// We try and store the token on a per-manager basis, but need a fallback
// for the default manager.
const configApiUrl = _SdkConfig.default.get("integrations_rest_url");
const configUiUrl = _SdkConfig.default.get("integrations_ui_url");
this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl;
}
writeTokenToStore() {
window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken ?? "");
if (this.isDefaultManager) {
// We remove the old token from storage to migrate upwards. This is safe
// to do because even if the user switches to /app when this is on /develop
// they'll at worst register for a new token.
window.localStorage.removeItem("mx_scalar_token"); // no-op when not present
}
}
readTokenFromStore() {
let token = window.localStorage.getItem("mx_scalar_token_at_" + this.apiUrl);
if (!token && this.isDefaultManager) {
token = window.localStorage.getItem("mx_scalar_token");
}
return token;
}
readToken() {
if (this.scalarToken) return this.scalarToken;
return this.readTokenFromStore();
}
setTermsInteractionCallback(callback) {
this.termsInteractionCallback = callback;
}
connect() {
return this.getScalarToken().then(tok => {
this.scalarToken = tok;
});
}
hasCredentials() {
return this.scalarToken != null; // undef or null
}
// Returns a promise that resolves to a scalar_token string
getScalarToken() {
const token = this.readToken();
if (!token) {
return this.registerForToken();
} else {
return this.checkToken(token).catch(e => {
if (e instanceof _Terms.TermsNotSignedError) {
// retrying won't help this
throw e;
}
return this.registerForToken();
});
}
}
async getAccountName(token) {
const url = new URL(this.apiUrl + "/account");
url.searchParams.set("scalar_token", token);
url.searchParams.set("v", imApiVersion);
const res = await fetch(url, {
method: "GET"
});
const body = await res.json();
if (body?.errcode === "M_TERMS_NOT_SIGNED") {
throw new _Terms.TermsNotSignedError();
}
if (!res.ok) {
throw body;
}
if (!body?.user_id) {
throw new Error("Missing user_id in response");
}
return body.user_id;
}
checkToken(token) {
return this.getAccountName(token).then(userId => {
const me = _MatrixClientPeg.MatrixClientPeg.safeGet().getUserId();
if (userId !== me) {
throw new Error("Scalar token is owned by someone else: " + me);
}
return token;
}).catch(e => {
if (e instanceof _Terms.TermsNotSignedError) {
_logger.logger.log("Integration manager requires new terms to be agreed to");
// The terms endpoints are new and so live on standard _matrix prefixes,
// but IM rest urls are currently configured with paths, so remove the
// path from the base URL before passing it to the js-sdk
// We continue to use the full URL for the calls done by
// matrix-react-sdk, but the standard terms API called
// by the js-sdk lives on the standard _matrix path. This means we
// don't support running IMs on a non-root path, but it's the only
// realistic way of transitioning to _matrix paths since configs in
// the wild contain bits of the API path.
// Once we've fully transitioned to _matrix URLs, we can give people
// a grace period to update their configs, then use the rest url as
// a regular base url.
const parsedImRestUrl = (0, _UrlUtils.parseUrl)(this.apiUrl);
parsedImRestUrl.pathname = "";
return (0, _Terms.startTermsFlow)(_MatrixClientPeg.MatrixClientPeg.safeGet(), [new _Terms.Service(_matrix.SERVICE_TYPES.IM, parsedImRestUrl.toString(), token)], this.termsInteractionCallback).then(() => {
return token;
});
} else {
throw e;
}
});
}
registerForToken() {
// Get openid bearer token from the HS as the first part of our dance
return _MatrixClientPeg.MatrixClientPeg.safeGet().getOpenIdToken().then(tokenObject => {
// Now we can send that to scalar and exchange it for a scalar token
return this.exchangeForScalarToken(tokenObject);
}).then(token => {
// Validate it (this mostly checks to see if the IM needs us to agree to some terms)
return this.checkToken(token);
}).then(token => {
this.scalarToken = token;
this.writeTokenToStore();
return token;
});
}
async exchangeForScalarToken(openidTokenObject) {
const scalarRestUrl = new URL(this.apiUrl + "/register");
scalarRestUrl.searchParams.set("v", imApiVersion);
const res = await fetch(scalarRestUrl, {
method: "POST",
body: JSON.stringify(openidTokenObject),
headers: {
"Content-Type": "application/json"
}
});
if (!res.ok) {
throw new Error(`Scalar request failed: ${res.status}`);
}
const body = await res.json();
if (!body?.scalar_token) {
throw new Error("Missing scalar_token in response");
}
return body.scalar_token;
}
async getScalarPageTitle(url) {
const scalarPageLookupUrl = new URL(this.getStarterLink(this.apiUrl + "/widgets/title_lookup"));
scalarPageLookupUrl.searchParams.set("curl", encodeURIComponent(url));
const res = await fetch(scalarPageLookupUrl, {
method: "GET"
});
if (!res.ok) {
throw new Error(`Scalar request failed: ${res.status}`);
}
const body = await res.json();
return body?.page_title_cache_item?.cached_title;
}
/**
* Mark all assets associated with the specified widget as "disabled" in the
* integration manager database.
* This can be useful to temporarily prevent purchased assets from being displayed.
* @param {WidgetType} widgetType The Widget Type to disable assets for
* @param {string} widgetId The widget ID to disable assets for
* @return {Promise} Resolves on completion
*/
async disableWidgetAssets(widgetType, widgetId) {
const url = new URL(this.getStarterLink(this.apiUrl + "/widgets/set_assets_state"));
url.searchParams.set("widget_type", widgetType.preferred);
url.searchParams.set("widget_id", widgetId);
url.searchParams.set("state", "disable");
const res = await fetch(url, {
method: "GET" // XXX: Actions shouldn't be GET requests
});
if (!res.ok) {
throw new Error(`Scalar request failed: ${res.status}`);
}
const body = await res.text();
if (!body) {
throw new Error("Failed to set widget assets state");
}
}
getScalarInterfaceUrlForRoom(room, screen, id) {
const roomId = room.roomId;
const roomName = room.name;
let url = this.uiUrl;
if (this.scalarToken) url += "?scalar_token=" + encodeURIComponent(this.scalarToken);
url += "&room_id=" + encodeURIComponent(roomId);
url += "&room_name=" + encodeURIComponent(roomName);
url += "&theme=" + encodeURIComponent(_SettingsStore.default.getValue("theme"));
if (id) {
url += "&integ_id=" + encodeURIComponent(id);
}
if (screen) {
url += "&screen=" + encodeURIComponent(screen);
}
return url;
}
getStarterLink(starterLinkUrl) {
if (!this.scalarToken) return starterLinkUrl;
return starterLinkUrl + "?scalar_token=" + encodeURIComponent(this.scalarToken);
}
}
exports.default = ScalarAuthClient;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfU2V0dGluZ3NTdG9yZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfVGVybXMiLCJfTWF0cml4Q2xpZW50UGVnIiwiX1Nka0NvbmZpZyIsIl9VcmxVdGlscyIsImltQXBpVmVyc2lvbiIsIlNjYWxhckF1dGhDbGllbnQiLCJjb25zdHJ1Y3RvciIsImFwaVVybCIsInVpVXJsIiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJzY2FsYXJUb2tlbiIsInRlcm1zSW50ZXJhY3Rpb25DYWxsYmFjayIsInVuZGVmaW5lZCIsImNvbmZpZ0FwaVVybCIsIlNka0NvbmZpZyIsImdldCIsImNvbmZpZ1VpVXJsIiwiaXNEZWZhdWx0TWFuYWdlciIsIndyaXRlVG9rZW5Ub1N0b3JlIiwid2luZG93IiwibG9jYWxTdG9yYWdlIiwic2V0SXRlbSIsInJlbW92ZUl0ZW0iLCJyZWFkVG9rZW5Gcm9tU3RvcmUiLCJ0b2tlbiIsImdldEl0ZW0iLCJyZWFkVG9rZW4iLCJzZXRUZXJtc0ludGVyYWN0aW9uQ2FsbGJhY2siLCJjYWxsYmFjayIsImNvbm5lY3QiLCJnZXRTY2FsYXJUb2tlbiIsInRoZW4iLCJ0b2siLCJoYXNDcmVkZW50aWFscyIsInJlZ2lzdGVyRm9yVG9rZW4iLCJjaGVja1Rva2VuIiwiY2F0Y2giLCJlIiwiVGVybXNOb3RTaWduZWRFcnJvciIsImdldEFjY291bnROYW1lIiwidXJsIiwiVVJMIiwic2VhcmNoUGFyYW1zIiwic2V0IiwicmVzIiwiZmV0Y2giLCJtZXRob2QiLCJib2R5IiwianNvbiIsImVycmNvZGUiLCJvayIsInVzZXJfaWQiLCJFcnJvciIsInVzZXJJZCIsIm1lIiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsImdldFVzZXJJZCIsImxvZ2dlciIsImxvZyIsInBhcnNlZEltUmVzdFVybCIsInBhcnNlVXJsIiwicGF0aG5hbWUiLCJzdGFydFRlcm1zRmxvdyIsIlNlcnZpY2UiLCJTRVJWSUNFX1RZUEVTIiwiSU0iLCJ0b1N0cmluZyIsImdldE9wZW5JZFRva2VuIiwidG9rZW5PYmplY3QiLCJleGNoYW5nZUZvclNjYWxhclRva2VuIiwib3BlbmlkVG9rZW5PYmplY3QiLCJzY2FsYXJSZXN0VXJsIiwiSlNPTiIsInN0cmluZ2lmeSIsImhlYWRlcnMiLCJzdGF0dXMiLCJzY2FsYXJfdG9rZW4iLCJnZXRTY2FsYXJQYWdlVGl0bGUiLCJzY2FsYXJQYWdlTG9va3VwVXJsIiwiZ2V0U3RhcnRlckxpbmsiLCJlbmNvZGVVUklDb21wb25lbnQiLCJwYWdlX3RpdGxlX2NhY2hlX2l0ZW0iLCJjYWNoZWRfdGl0bGUiLCJkaXNhYmxlV2lkZ2V0QXNzZXRzIiwid2lkZ2V0VHlwZSIsIndpZGdldElkIiwicHJlZmVycmVkIiwidGV4dCIsImdldFNjYWxhckludGVyZmFjZVVybEZvclJvb20iLCJyb29tIiwic2NyZWVuIiwiaWQiLCJyb29tSWQiLCJyb29tTmFtZSIsIm5hbWUiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJzdGFydGVyTGlua1VybCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi9zcmMvU2NhbGFyQXV0aENsaWVudC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxNi0yMDE5ICwgMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBTRVJWSUNFX1RZUEVTLCBSb29tLCBJT3BlbklEVG9rZW4gfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5cbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IFNlcnZpY2UsIHN0YXJ0VGVybXNGbG93LCBUZXJtc0ludGVyYWN0aW9uQ2FsbGJhY2ssIFRlcm1zTm90U2lnbmVkRXJyb3IgfSBmcm9tIFwiLi9UZXJtc1wiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgU2RrQ29uZmlnIGZyb20gXCIuL1Nka0NvbmZpZ1wiO1xuaW1wb3J0IHsgV2lkZ2V0VHlwZSB9IGZyb20gXCIuL3dpZGdldHMvV2lkZ2V0VHlwZVwiO1xuaW1wb3J0IHsgcGFyc2VVcmwgfSBmcm9tIFwiLi91dGlscy9VcmxVdGlsc1wiO1xuXG4vLyBUaGUgdmVyc2lvbiBvZiB0aGUgaW50ZWdyYXRpb24gbWFuYWdlciBBUEkgd2UncmUgaW50ZW5kaW5nIHRvIHdvcmsgd2l0aFxuY29uc3QgaW1BcGlWZXJzaW9uID0gXCIxLjFcIjtcblxuLy8gVE9ETzogR2VuZXJpZnkgdGhlIG5hbWUgb2YgdGhpcyBjbGFzcyBhbmQgYWxsIGNvbXBvbmVudHMgd2l0aGluIC0gaXQncyBub3QganVzdCBmb3IgU2NhbGFyLlxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTY2FsYXJBdXRoQ2xpZW50IHtcbiAgICBwcml2YXRlIHNjYWxhclRva2VuOiBzdHJpbmcgfCBudWxsO1xuICAgIHByaXZhdGUgdGVybXNJbnRlcmFjdGlvbkNhbGxiYWNrPzogVGVybXNJbnRlcmFjdGlvbkNhbGxiYWNrO1xuICAgIHByaXZhdGUgaXNEZWZhdWx0TWFuYWdlcjogYm9vbGVhbjtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBhcGlVcmw6IHN0cmluZyxcbiAgICAgICAgcHJpdmF0ZSB1aVVybDogc3RyaW5nLFxuICAgICkge1xuICAgICAgICB0aGlzLnNjYWxhclRva2VuID0gbnVsbDtcbiAgICAgICAgLy8gYHVuZGVmaW5lZGAgdG8gYWxsb3cgYHN0YXJ0VGVybXNGbG93YCB0byBmYWxsYmFjayB0byBhIGRlZmF1bHRcbiAgICAgICAgLy8gY2FsbGJhY2sgaWYgdGhpcyBpcyB1bnNldC5cbiAgICAgICAgdGhpcy50ZXJtc0ludGVyYWN0aW9uQ2FsbGJhY2sgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gV2UgdHJ5IGFuZCBzdG9yZSB0aGUgdG9rZW4gb24gYSBwZXItbWFuYWdlciBiYXNpcywgYnV0IG5lZWQgYSBmYWxsYmFja1xuICAgICAgICAvLyBmb3IgdGhlIGRlZmF1bHQgbWFuYWdlci5cbiAgICAgICAgY29uc3QgY29uZmlnQXBpVXJsID0gU2RrQ29uZmlnLmdldChcImludGVncmF0aW9uc19yZXN0X3VybFwiKTtcbiAgICAgICAgY29uc3QgY29uZmlnVWlVcmwgPSBTZGtDb25maWcuZ2V0KFwiaW50ZWdyYXRpb25zX3VpX3VybFwiKTtcbiAgICAgICAgdGhpcy5pc0RlZmF1bHRNYW5hZ2VyID0gYXBpVXJsID09PSBjb25maWdBcGlVcmwgJiYgY29uZmlnVWlVcmwgPT09IHVpVXJsO1xuICAgIH1cblxuICAgIHByaXZhdGUgd3JpdGVUb2tlblRvU3RvcmUoKTogdm9pZCB7XG4gICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShcIm14X3NjYWxhcl90b2tlbl9hdF9cIiArIHRoaXMuYXBpVXJsLCB0aGlzLnNjYWxhclRva2VuID8/IFwiXCIpO1xuICAgICAgICBpZiAodGhpcy5pc0RlZmF1bHRNYW5hZ2VyKSB7XG4gICAgICAgICAgICAvLyBXZSByZW1vdmUgdGhlIG9sZCB0b2tlbiBmcm9tIHN0b3JhZ2UgdG8gbWlncmF0ZSB1cHdhcmRzLiBUaGlzIGlzIHNhZmVcbiAgICAgICAgICAgIC8vIHRvIGRvIGJlY2F1c2UgZXZlbiBpZiB0aGUgdXNlciBzd2l0Y2hlcyB0byAvYXBwIHdoZW4gdGhpcyBpcyBvbiAvZGV2ZWxvcFxuICAgICAgICAgICAgLy8gdGhleSdsbCBhdCB3b3JzdCByZWdpc3RlciBmb3IgYSBuZXcgdG9rZW4uXG4gICAgICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oXCJteF9zY2FsYXJfdG9rZW5cIik7IC8vIG5vLW9wIHdoZW4gbm90IHByZXNlbnRcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgcmVhZFRva2VuRnJvbVN0b3JlKCk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICBsZXQgdG9rZW4gPSB3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJteF9zY2FsYXJfdG9rZW5fYXRfXCIgKyB0aGlzLmFwaVVybCk7XG4gICAgICAgIGlmICghdG9rZW4gJiYgdGhpcy5pc0RlZmF1bHRNYW5hZ2VyKSB7XG4gICAgICAgICAgICB0b2tlbiA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcIm14X3NjYWxhcl90b2tlblwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWFkVG9rZW4oKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIGlmICh0aGlzLnNjYWxhclRva2VuKSByZXR1cm4gdGhpcy5zY2FsYXJUb2tlbjtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVhZFRva2VuRnJvbVN0b3JlKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldFRlcm1zSW50ZXJhY3Rpb25DYWxsYmFjayhjYWxsYmFjazogVGVybXNJbnRlcmFjdGlvbkNhbGxiYWNrKTogdm9pZCB7XG4gICAgICAgIHRoaXMudGVybXNJbnRlcmFjdGlvbkNhbGxiYWNrID0gY2FsbGJhY2s7XG4gICAgfVxuXG4gICAgcHVibGljIGNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFNjYWxhclRva2VuKCkudGhlbigodG9rKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNjYWxhclRva2VuID0gdG9rO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzQ3JlZGVudGlhbHMoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnNjYWxhclRva2VuICE9IG51bGw7IC8vIHVuZGVmIG9yIG51bGxcbiAgICB9XG5cbiAgICAvLyBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgc2NhbGFyX3Rva2VuIHN0cmluZ1xuICAgIHB1YmxpYyBnZXRTY2FsYXJUb2tlbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICBjb25zdCB0b2tlbiA9IHRoaXMucmVhZFRva2VuKCk7XG5cbiAgICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVnaXN0ZXJGb3JUb2tlbigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2hlY2tUb2tlbih0b2tlbikuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZSBpbnN0YW5jZW9mIFRlcm1zTm90U2lnbmVkRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gcmV0cnlpbmcgd29uJ3QgaGVscCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlZ2lzdGVyRm9yVG9rZW4oKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBnZXRBY2NvdW50TmFtZSh0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTCh0aGlzLmFwaVVybCArIFwiL2FjY291bnRcIik7XG4gICAgICAgIHVybC5zZWFyY2hQYXJhbXMuc2V0KFwic2NhbGFyX3Rva2VuXCIsIHRva2VuKTtcbiAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoXCJ2XCIsIGltQXBpVmVyc2lvbik7XG5cbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXMuanNvbigpO1xuICAgICAgICBpZiAoYm9keT8uZXJyY29kZSA9PT0gXCJNX1RFUk1TX05PVF9TSUdORURcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFRlcm1zTm90U2lnbmVkRXJyb3IoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghcmVzLm9rKSB7XG4gICAgICAgICAgICB0aHJvdyBib2R5O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFib2R5Py51c2VyX2lkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNaXNzaW5nIHVzZXJfaWQgaW4gcmVzcG9uc2VcIik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYm9keS51c2VyX2lkO1xuICAgIH1cblxuICAgIHByaXZhdGUgY2hlY2tUb2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QWNjb3VudE5hbWUodG9rZW4pXG4gICAgICAgICAgICAudGhlbigodXNlcklkKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbWUgPSBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldFVzZXJJZCgpO1xuICAgICAgICAgICAgICAgIGlmICh1c2VySWQgIT09IG1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlNjYWxhciB0b2tlbiBpcyBvd25lZCBieSBzb21lb25lIGVsc2U6IFwiICsgbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBUZXJtc05vdFNpZ25lZEVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJJbnRlZ3JhdGlvbiBtYW5hZ2VyIHJlcXVpcmVzIG5ldyB0ZXJtcyB0byBiZSBhZ3JlZWQgdG9cIik7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSB0ZXJtcyBlbmRwb2ludHMgYXJlIG5ldyBhbmQgc28gbGl2ZSBvbiBzdGFuZGFyZCBfbWF0cml4IHByZWZpeGVzLFxuICAgICAgICAgICAgICAgICAgICAvLyBidXQgSU0gcmVzdCB1cmxzIGFyZSBjdXJyZW50bHkgY29uZmlndXJlZCB3aXRoIHBhdGhzLCBzbyByZW1vdmUgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBhdGggZnJvbSB0aGUgYmFzZSBVUkwgYmVmb3JlIHBhc3NpbmcgaXQgdG8gdGhlIGpzLXNka1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFdlIGNvbnRpbnVlIHRvIHVzZSB0aGUgZnVsbCBVUkwgZm9yIHRoZSBjYWxscyBkb25lIGJ5XG4gICAgICAgICAgICAgICAgICAgIC8vIG1hdHJpeC1yZWFjdC1zZGssIGJ1dCB0aGUgc3RhbmRhcmQgdGVybXMgQVBJIGNhbGxlZFxuICAgICAgICAgICAgICAgICAgICAvLyBieSB0aGUganMtc2RrIGxpdmVzIG9uIHRoZSBzdGFuZGFyZCBfbWF0cml4IHBhdGguIFRoaXMgbWVhbnMgd2VcbiAgICAgICAgICAgICAgICAgICAgLy8gZG9uJ3Qgc3VwcG9ydCBydW5uaW5nIElNcyBvbiBhIG5vbi1yb290IHBhdGgsIGJ1dCBpdCdzIHRoZSBvbmx5XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlYWxpc3RpYyB3YXkgb2YgdHJhbnNpdGlvbmluZyB0byBfbWF0cml4IHBhdGhzIHNpbmNlIGNvbmZpZ3MgaW5cbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIHdpbGQgY29udGFpbiBiaXRzIG9mIHRoZSBBUEkgcGF0aC5cblxuICAgICAgICAgICAgICAgICAgICAvLyBPbmNlIHdlJ3ZlIGZ1bGx5IHRyYW5zaXRpb25lZCB0byBfbWF0cml4IFVSTHMsIHdlIGNhbiBnaXZlIHBlb3BsZVxuICAgICAgICAgICAgICAgICAgICAvLyBhIGdyYWNlIHBlcmlvZCB0byB1cGRhdGUgdGhlaXIgY29uZmlncywgdGhlbiB1c2UgdGhlIHJlc3QgdXJsIGFzXG4gICAgICAgICAgICAgICAgICAgIC8vIGEgcmVndWxhciBiYXNlIHVybC5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFyc2VkSW1SZXN0VXJsID0gcGFyc2VVcmwodGhpcy5hcGlVcmwpO1xuICAgICAgICAgICAgICAgICAgICBwYXJzZWRJbVJlc3RVcmwucGF0aG5hbWUgPSBcIlwiO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc3RhcnRUZXJtc0Zsb3coXG4gICAgICAgICAgICAgICAgICAgICAgICBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgW25ldyBTZXJ2aWNlKFNFUlZJQ0VfVFlQRVMuSU0sIHBhcnNlZEltUmVzdFVybC50b1N0cmluZygpLCB0b2tlbildLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy50ZXJtc0ludGVyYWN0aW9uQ2FsbGJhY2ssXG4gICAgICAgICAgICAgICAgICAgICkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlZ2lzdGVyRm9yVG9rZW4oKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgLy8gR2V0IG9wZW5pZCBiZWFyZXIgdG9rZW4gZnJvbSB0aGUgSFMgYXMgdGhlIGZpcnN0IHBhcnQgb2Ygb3VyIGRhbmNlXG4gICAgICAgIHJldHVybiBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpXG4gICAgICAgICAgICAuZ2V0T3BlbklkVG9rZW4oKVxuICAgICAgICAgICAgLnRoZW4oKHRva2VuT2JqZWN0KSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gTm93IHdlIGNhbiBzZW5kIHRoYXQgdG8gc2NhbGFyIGFuZCBleGNoYW5nZSBpdCBmb3IgYSBzY2FsYXIgdG9rZW5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5leGNoYW5nZUZvclNjYWxhclRva2VuKHRva2VuT2JqZWN0KTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbigodG9rZW4pID0+IHtcbiAgICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSBpdCAodGhpcyBtb3N0bHkgY2hlY2tzIHRvIHNlZSBpZiB0aGUgSU0gbmVlZHMgdXMgdG8gYWdyZWUgdG8gc29tZSB0ZXJtcylcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jaGVja1Rva2VuKHRva2VuKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbigodG9rZW4pID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNjYWxhclRva2VuID0gdG9rZW47XG4gICAgICAgICAgICAgICAgdGhpcy53cml0ZVRva2VuVG9TdG9yZSgpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbjtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBleGNoYW5nZUZvclNjYWxhclRva2VuKG9wZW5pZFRva2VuT2JqZWN0OiBJT3BlbklEVG9rZW4pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICBjb25zdCBzY2FsYXJSZXN0VXJsID0gbmV3IFVSTCh0aGlzLmFwaVVybCArIFwiL3JlZ2lzdGVyXCIpO1xuICAgICAgICBzY2FsYXJSZXN0VXJsLnNlYXJjaFBhcmFtcy5zZXQoXCJ2XCIsIGltQXBpVmVyc2lvbik7XG5cbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goc2NhbGFyUmVzdFVybCwge1xuICAgICAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KG9wZW5pZFRva2VuT2JqZWN0KSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghcmVzLm9rKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNjYWxhciByZXF1ZXN0IGZhaWxlZDogJHtyZXMuc3RhdHVzfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYm9keSA9IGF3YWl0IHJlcy5qc29uKCk7XG4gICAgICAgIGlmICghYm9keT8uc2NhbGFyX3Rva2VuKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNaXNzaW5nIHNjYWxhcl90b2tlbiBpbiByZXNwb25zZVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBib2R5LnNjYWxhcl90b2tlbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0U2NhbGFyUGFnZVRpdGxlKHVybDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3Qgc2NhbGFyUGFnZUxvb2t1cFVybCA9IG5ldyBVUkwodGhpcy5nZXRTdGFydGVyTGluayh0aGlzLmFwaVVybCArIFwiL3dpZGdldHMvdGl0bGVfbG9va3VwXCIpKTtcbiAgICAgICAgc2NhbGFyUGFnZUxvb2t1cFVybC5zZWFyY2hQYXJhbXMuc2V0KFwiY3VybFwiLCBlbmNvZGVVUklDb21wb25lbnQodXJsKSk7XG5cbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goc2NhbGFyUGFnZUxvb2t1cFVybCwge1xuICAgICAgICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIXJlcy5vaykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTY2FsYXIgcmVxdWVzdCBmYWlsZWQ6ICR7cmVzLnN0YXR1c31gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXMuanNvbigpO1xuICAgICAgICByZXR1cm4gYm9keT8ucGFnZV90aXRsZV9jYWNoZV9pdGVtPy5jYWNoZWRfdGl0bGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFyayBhbGwgYXNzZXRzIGFzc29jaWF0ZWQgd2l0aCB0aGUgc3BlY2lmaWVkIHdpZGdldCBhcyBcImRpc2FibGVkXCIgaW4gdGhlXG4gICAgICogaW50ZWdyYXRpb24gbWFuYWdlciBkYXRhYmFzZS5cbiAgICAgKiBUaGlzIGNhbiBiZSB1c2VmdWwgdG8gdGVtcG9yYXJpbHkgcHJldmVudCBwdXJjaGFzZWQgYXNzZXRzIGZyb20gYmVpbmcgZGlzcGxheWVkLlxuICAgICAqIEBwYXJhbSAge1dpZGdldFR5cGV9IHdpZGdldFR5cGUgVGhlIFdpZGdldCBUeXBlIHRvIGRpc2FibGUgYXNzZXRzIGZvclxuICAgICAqIEBwYXJhbSAge3N0cmluZ30gd2lkZ2V0SWQgICBUaGUgd2lkZ2V0IElEIHRvIGRpc2FibGUgYXNzZXRzIGZvclxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9ICAgICAgICAgICBSZXNvbHZlcyBvbiBjb21wbGV0aW9uXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGRpc2FibGVXaWRnZXRBc3NldHMod2lkZ2V0VHlwZTogV2lkZ2V0VHlwZSwgd2lkZ2V0SWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHRoaXMuZ2V0U3RhcnRlckxpbmsodGhpcy5hcGlVcmwgKyBcIi93aWRnZXRzL3NldF9hc3NldHNfc3RhdGVcIikpO1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLnNldChcIndpZGdldF90eXBlXCIsIHdpZGdldFR5cGUucHJlZmVycmVkKTtcbiAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoXCJ3aWRnZXRfaWRcIiwgd2lkZ2V0SWQpO1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLnNldChcInN0YXRlXCIsIFwiZGlzYWJsZVwiKTtcblxuICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgICAgICAgIG1ldGhvZDogXCJHRVRcIiwgLy8gWFhYOiBBY3Rpb25zIHNob3VsZG4ndCBiZSBHRVQgcmVxdWVzdHNcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKCFyZXMub2spIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2NhbGFyIHJlcXVlc3QgZmFpbGVkOiAke3Jlcy5zdGF0dXN9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBib2R5ID0gYXdhaXQgcmVzLnRleHQoKTtcbiAgICAgICAgaWYgKCFib2R5KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGYWlsZWQgdG8gc2V0IHdpZGdldCBhc3NldHMgc3RhdGVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0U2NhbGFySW50ZXJmYWNlVXJsRm9yUm9vbShyb29tOiBSb29tLCBzY3JlZW4/OiBzdHJpbmcsIGlkPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3Qgcm9vbUlkID0gcm9vbS5yb29tSWQ7XG4gICAgICAgIGNvbnN0IHJvb21OYW1lID0gcm9vbS5uYW1lO1xuICAgICAgICBsZXQgdXJsID0gdGhpcy51aVVybDtcbiAgICAgICAgaWYgKHRoaXMuc2NhbGFyVG9rZW4pIHVybCArPSBcIj9zY2FsYXJfdG9rZW49XCIgKyBlbmNvZGVVUklDb21wb25lbnQodGhpcy5zY2FsYXJUb2tlbik7XG4gICAgICAgIHVybCArPSBcIiZyb29tX2lkPVwiICsgZW5jb2RlVVJJQ29tcG9uZW50KHJvb21JZCk7XG4gICAgICAgIHVybCArPSBcIiZyb29tX25hbWU9XCIgKyBlbmNvZGVVUklDb21wb25lbnQocm9vbU5hbWUpO1xuICAgICAgICB1cmwgKz0gXCImdGhlbWU9XCIgKyBlbmNvZGVVUklDb21wb25lbnQoU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInRoZW1lXCIpKTtcbiAgICAgICAgaWYgKGlkKSB7XG4gICAgICAgICAgICB1cmwgKz0gXCImaW50ZWdfaWQ9XCIgKyBlbmNvZGVVUklDb21wb25lbnQoaWQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzY3JlZW4pIHtcbiAgICAgICAgICAgIHVybCArPSBcIiZzY3JlZW49XCIgKyBlbmNvZGVVUklDb21wb25lbnQoc2NyZWVuKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTdGFydGVyTGluayhzdGFydGVyTGlua1VybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKCF0aGlzLnNjYWxhclRva2VuKSByZXR1cm4gc3RhcnRlckxpbmtVcmw7XG4gICAgICAgIHJldHVybiBzdGFydGVyTGlua1VybCArIFwiP3NjYWxhcl90b2tlbj1cIiArIGVuY29kZVVSSUNvbXBvbmVudCh0aGlzLnNjYWxhclRva2VuKTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBRUEsSUFBQUUsY0FBQSxHQUFBQyxzQkFBQSxDQUFBSCxPQUFBO0FBQ0EsSUFBQUksTUFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssZ0JBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLFVBQUEsR0FBQUgsc0JBQUEsQ0FBQUgsT0FBQTtBQUVBLElBQUFPLFNBQUEsR0FBQVAsT0FBQTtBQWhCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFZQTtBQUNBLE1BQU1RLFlBQVksR0FBRyxLQUFLOztBQUUxQjs7QUFFZSxNQUFNQyxnQkFBZ0IsQ0FBQztFQUszQkMsV0FBV0EsQ0FDTkMsTUFBYyxFQUNkQyxLQUFhLEVBQ3ZCO0lBQUEsSUFBQUMsZ0JBQUEsQ0FBQUMsT0FBQTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUE7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsS0FGVUgsTUFBYyxHQUFkQSxNQUFjO0lBQUEsS0FDZEMsS0FBYSxHQUFiQSxLQUFhO0lBRXJCLElBQUksQ0FBQ0csV0FBVyxHQUFHLElBQUk7SUFDdkI7SUFDQTtJQUNBLElBQUksQ0FBQ0Msd0JBQXdCLEdBQUdDLFNBQVM7O0lBRXpDO0lBQ0E7SUFDQSxNQUFNQyxZQUFZLEdBQUdDLGtCQUFTLENBQUNDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQztJQUMzRCxNQUFNQyxXQUFXLEdBQUdGLGtCQUFTLENBQUNDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQztJQUN4RCxJQUFJLENBQUNFLGdCQUFnQixHQUFHWCxNQUFNLEtBQUtPLFlBQVksSUFBSUcsV0FBVyxLQUFLVCxLQUFLO0VBQzVFO0VBRVFXLGlCQUFpQkEsQ0FBQSxFQUFTO0lBQzlCQyxNQUFNLENBQUNDLFlBQVksQ0FBQ0MsT0FBTyxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQ2YsTUFBTSxFQUFFLElBQUksQ0FBQ0ksV0FBVyxJQUFJLEVBQUUsQ0FBQztJQUN4RixJQUFJLElBQUksQ0FBQ08sZ0JBQWdCLEVBQUU7TUFDdkI7TUFDQTtNQUNBO01BQ0FFLE1BQU0sQ0FBQ0MsWUFBWSxDQUFDRSxVQUFVLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDO0lBQ3ZEO0VBQ0o7RUFFUUMsa0JBQWtCQSxDQUFBLEVBQWtCO0lBQ3hDLElBQUlDLEtBQUssR0FBR0wsTUFBTSxDQUFDQyxZQUFZLENBQUNLLE9BQU8sQ0FBQyxxQkFBcUIsR0FBRyxJQUFJLENBQUNuQixNQUFNLENBQUM7SUFDNUUsSUFBSSxDQUFDa0IsS0FBSyxJQUFJLElBQUksQ0FBQ1AsZ0JBQWdCLEVBQUU7TUFDakNPLEtBQUssR0FBR0wsTUFBTSxDQUFDQyxZQUFZLENBQUNLLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztJQUMxRDtJQUNBLE9BQU9ELEtBQUs7RUFDaEI7RUFFUUUsU0FBU0EsQ0FBQSxFQUFrQjtJQUMvQixJQUFJLElBQUksQ0FBQ2hCLFdBQVcsRUFBRSxPQUFPLElBQUksQ0FBQ0EsV0FBVztJQUM3QyxPQUFPLElBQUksQ0FBQ2Esa0JBQWtCLENBQUMsQ0FBQztFQUNwQztFQUVPSSwyQkFBMkJBLENBQUNDLFFBQWtDLEVBQVE7SUFDekUsSUFBSSxDQUFDakIsd0JBQXdCLEdBQUdpQixRQUFRO0VBQzVDO0VBRU9DLE9BQU9BLENBQUEsRUFBa0I7SUFDNUIsT0FBTyxJQUFJLENBQUNDLGNBQWMsQ0FBQyxDQUFDLENBQUNDLElBQUksQ0FBRUMsR0FBRyxJQUFLO01BQ3ZDLElBQUksQ0FBQ3RCLFdBQVcsR0FBR3NCLEdBQUc7SUFDMUIsQ0FBQyxDQUFDO0VBQ047RUFFT0MsY0FBY0EsQ0FBQSxFQUFZO0lBQzdCLE9BQU8sSUFBSSxDQUFDdkIsV0FBVyxJQUFJLElBQUksQ0FBQyxDQUFDO0VBQ3JDOztFQUVBO0VBQ09vQixjQUFjQSxDQUFBLEVBQW9CO0lBQ3JDLE1BQU1OLEtBQUssR0FBRyxJQUFJLENBQUNFLFNBQVMsQ0FBQyxDQUFDO0lBRTlCLElBQUksQ0FBQ0YsS0FBSyxFQUFFO01BQ1IsT0FBTyxJQUFJLENBQUNVLGdCQUFnQixDQUFDLENBQUM7SUFDbEMsQ0FBQyxNQUFNO01BQ0gsT0FBTyxJQUFJLENBQUNDLFVBQVUsQ0FBQ1gsS0FBSyxDQUFDLENBQUNZLEtBQUssQ0FBRUMsQ0FBQyxJQUFLO1FBQ3ZDLElBQUlBLENBQUMsWUFBWUMsMEJBQW1CLEVBQUU7VUFDbEM7VUFDQSxNQUFNRCxDQUFDO1FBQ1g7UUFDQSxPQUFPLElBQUksQ0FBQ0gsZ0JBQWdCLENBQUMsQ0FBQztNQUNsQyxDQUFDLENBQUM7SUFDTjtFQUNKO0VBRUEsTUFBY0ssY0FBY0EsQ0FBQ2YsS0FBYSxFQUFtQjtJQUN6RCxNQUFNZ0IsR0FBRyxHQUFHLElBQUlDLEdBQUcsQ0FBQyxJQUFJLENBQUNuQyxNQUFNLEdBQUcsVUFBVSxDQUFDO0lBQzdDa0MsR0FBRyxDQUFDRSxZQUFZLENBQUNDLEdBQUcsQ0FBQyxjQUFjLEVBQUVuQixLQUFLLENBQUM7SUFDM0NnQixHQUFHLENBQUNFLFlBQVksQ0FBQ0MsR0FBRyxDQUFDLEdBQUcsRUFBRXhDLFlBQVksQ0FBQztJQUV2QyxNQUFNeUMsR0FBRyxHQUFHLE1BQU1DLEtBQUssQ0FBQ0wsR0FBRyxFQUFFO01BQ3pCTSxNQUFNLEVBQUU7SUFDWixDQUFDLENBQUM7SUFFRixNQUFNQyxJQUFJLEdBQUcsTUFBTUgsR0FBRyxDQUFDSSxJQUFJLENBQUMsQ0FBQztJQUM3QixJQUFJRCxJQUFJLEVBQUVFLE9BQU8sS0FBSyxvQkFBb0IsRUFBRTtNQUN4QyxNQUFNLElBQUlYLDBCQUFtQixDQUFDLENBQUM7SUFDbkM7SUFFQSxJQUFJLENBQUNNLEdBQUcsQ0FBQ00sRUFBRSxFQUFFO01BQ1QsTUFBTUgsSUFBSTtJQUNkO0lBRUEsSUFBSSxDQUFDQSxJQUFJLEVBQUVJLE9BQU8sRUFBRTtNQUNoQixNQUFNLElBQUlDLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQztJQUNsRDtJQUVBLE9BQU9MLElBQUksQ0FBQ0ksT0FBTztFQUN2QjtFQUVRaEIsVUFBVUEsQ0FBQ1gsS0FBYSxFQUFtQjtJQUMvQyxPQUFPLElBQUksQ0FBQ2UsY0FBYyxDQUFDZixLQUFLLENBQUMsQ0FDNUJPLElBQUksQ0FBRXNCLE1BQU0sSUFBSztNQUNkLE1BQU1DLEVBQUUsR0FBR0MsZ0NBQWUsQ0FBQ0MsT0FBTyxDQUFDLENBQUMsQ0FBQ0MsU0FBUyxDQUFDLENBQUM7TUFDaEQsSUFBSUosTUFBTSxLQUFLQyxFQUFFLEVBQUU7UUFDZixNQUFNLElBQUlGLEtBQUssQ0FBQyx5Q0FBeUMsR0FBR0UsRUFBRSxDQUFDO01BQ25FO01BQ0EsT0FBTzlCLEtBQUs7SUFDaEIsQ0FBQyxDQUFDLENBQ0RZLEtBQUssQ0FBRUMsQ0FBQyxJQUFLO01BQ1YsSUFBSUEsQ0FBQyxZQUFZQywwQkFBbUIsRUFBRTtRQUNsQ29CLGNBQU0sQ0FBQ0MsR0FBRyxDQUFDLHdEQUF3RCxDQUFDO1FBQ3BFO1FBQ0E7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBO1FBQ0EsTUFBTUMsZUFBZSxHQUFHLElBQUFDLGtCQUFRLEVBQUMsSUFBSSxDQUFDdkQsTUFBTSxDQUFDO1FBQzdDc0QsZUFBZSxDQUFDRSxRQUFRLEdBQUcsRUFBRTtRQUM3QixPQUFPLElBQUFDLHFCQUFjLEVBQ2pCUixnQ0FBZSxDQUFDQyxPQUFPLENBQUMsQ0FBQyxFQUN6QixDQUFDLElBQUlRLGNBQU8sQ0FBQ0MscUJBQWEsQ0FBQ0MsRUFBRSxFQUFFTixlQUFlLENBQUNPLFFBQVEsQ0FBQyxDQUFDLEVBQUUzQyxLQUFLLENBQUMsQ0FBQyxFQUNsRSxJQUFJLENBQUNiLHdCQUNULENBQUMsQ0FBQ29CLElBQUksQ0FBQyxNQUFNO1VBQ1QsT0FBT1AsS0FBSztRQUNoQixDQUFDLENBQUM7TUFDTixDQUFDLE1BQU07UUFDSCxNQUFNYSxDQUFDO01BQ1g7SUFDSixDQUFDLENBQUM7RUFDVjtFQUVPSCxnQkFBZ0JBLENBQUEsRUFBb0I7SUFDdkM7SUFDQSxPQUFPcUIsZ0NBQWUsQ0FBQ0MsT0FBTyxDQUFDLENBQUMsQ0FDM0JZLGNBQWMsQ0FBQyxDQUFDLENBQ2hCckMsSUFBSSxDQUFFc0MsV0FBVyxJQUFLO01BQ25CO01BQ0EsT0FBTyxJQUFJLENBQUNDLHNCQUFzQixDQUFDRCxXQUFXLENBQUM7SUFDbkQsQ0FBQyxDQUFDLENBQ0R0QyxJQUFJLENBQUVQLEtBQUssSUFBSztNQUNiO01BQ0EsT0FBTyxJQUFJLENBQUNXLFVBQVUsQ0FBQ1gsS0FBSyxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUNETyxJQUFJLENBQUVQLEtBQUssSUFBSztNQUNiLElBQUksQ0FBQ2QsV0FBVyxHQUFHYyxLQUFLO01BQ3hCLElBQUksQ0FBQ04saUJBQWlCLENBQUMsQ0FBQztNQUN4QixPQUFPTSxLQUFLO0lBQ2hCLENBQUMsQ0FBQztFQUNWO0VBRUEsTUFBYThDLHNCQUFzQkEsQ0FBQ0MsaUJBQStCLEVBQW1CO0lBQ2xGLE1BQU1DLGFBQWEsR0FBRyxJQUFJL0IsR0FBRyxDQUFDLElBQUksQ0FBQ25DLE1BQU0sR0FBRyxXQUFXLENBQUM7SUFDeERrRSxhQUFhLENBQUM5QixZQUFZLENBQUNDLEdBQUcsQ0FBQyxHQUFHLEVBQUV4QyxZQUFZLENBQUM7SUFFakQsTUFBTXlDLEdBQUcsR0FBRyxNQUFNQyxLQUFLLENBQUMyQixhQUFhLEVBQUU7TUFDbkMxQixNQUFNLEVBQUUsTUFBTTtNQUNkQyxJQUFJLEVBQUUwQixJQUFJLENBQUNDLFNBQVMsQ0FBQ0gsaUJBQWlCLENBQUM7TUFDdkNJLE9BQU8sRUFBRTtRQUNMLGNBQWMsRUFBRTtNQUNwQjtJQUNKLENBQUMsQ0FBQztJQUVGLElBQUksQ0FBQy9CLEdBQUcsQ0FBQ00sRUFBRSxFQUFFO01BQ1QsTUFBTSxJQUFJRSxLQUFLLENBQUMsMEJBQTBCUixHQUFHLENBQUNnQyxNQUFNLEVBQUUsQ0FBQztJQUMzRDtJQUVBLE1BQU03QixJQUFJLEdBQUcsTUFBTUgsR0FBRyxDQUFDSSxJQUFJLENBQUMsQ0FBQztJQUM3QixJQUFJLENBQUNELElBQUksRUFBRThCLFlBQVksRUFBRTtNQUNyQixNQUFNLElBQUl6QixLQUFLLENBQUMsa0NBQWtDLENBQUM7SUFDdkQ7SUFFQSxPQUFPTCxJQUFJLENBQUM4QixZQUFZO0VBQzVCO0VBRUEsTUFBYUMsa0JBQWtCQSxDQUFDdEMsR0FBVyxFQUFtQjtJQUMxRCxNQUFNdUMsbUJBQW1CLEdBQUcsSUFBSXRDLEdBQUcsQ0FBQyxJQUFJLENBQUN1QyxjQUFjLENBQUMsSUFBSSxDQUFDMUUsTUFBTSxHQUFHLHVCQUF1QixDQUFDLENBQUM7SUFDL0Z5RSxtQkFBbUIsQ0FBQ3JDLFlBQVksQ0FBQ0MsR0FBRyxDQUFDLE1BQU0sRUFBRXNDLGtCQUFrQixDQUFDekMsR0FBRyxDQUFDLENBQUM7SUFFckUsTUFBTUksR0FBRyxHQUFHLE1BQU1DLEtBQUssQ0FBQ2tDLG1CQUFtQixFQUFFO01BQ3pDakMsTUFBTSxFQUFFO0lBQ1osQ0FBQyxDQUFDO0lBRUYsSUFBSSxDQUFDRixHQUFHLENBQUNNLEVBQUUsRUFBRTtNQUNULE1BQU0sSUFBSUUsS0FBSyxDQUFDLDBCQUEwQlIsR0FBRyxDQUFDZ0MsTUFBTSxFQUFFLENBQUM7SUFDM0Q7SUFFQSxNQUFNN0IsSUFBSSxHQUFHLE1BQU1ILEdBQUcsQ0FBQ0ksSUFBSSxDQUFDLENBQUM7SUFDN0IsT0FBT0QsSUFBSSxFQUFFbUMscUJBQXFCLEVBQUVDLFlBQVk7RUFDcEQ7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNJLE1BQWFDLG1CQUFtQkEsQ0FBQ0MsVUFBc0IsRUFBRUMsUUFBZ0IsRUFBaUI7SUFDdEYsTUFBTTlDLEdBQUcsR0FBRyxJQUFJQyxHQUFHLENBQUMsSUFBSSxDQUFDdUMsY0FBYyxDQUFDLElBQUksQ0FBQzFFLE1BQU0sR0FBRywyQkFBMkIsQ0FBQyxDQUFDO0lBQ25Ga0MsR0FBRyxDQUFDRSxZQUFZLENBQUNDLEdBQUcsQ0FBQyxhQUFhLEVBQUUwQyxVQUFVLENBQUNFLFNBQVMsQ0FBQztJQUN6RC9DLEdBQUcsQ0FBQ0UsWUFBWSxDQUFDQyxHQUFHLENBQUMsV0FBVyxFQUFFMkMsUUFBUSxDQUFDO0lBQzNDOUMsR0FBRyxDQUFDRSxZQUFZLENBQUNDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDO0lBRXhDLE1BQU1DLEdBQUcsR0FBRyxNQUFNQyxLQUFLLENBQUNMLEdBQUcsRUFBRTtNQUN6Qk0sTUFBTSxFQUFFLEtBQUssQ0FBRTtJQUNuQixDQUFDLENBQUM7SUFFRixJQUFJLENBQUNGLEdBQUcsQ0FBQ00sRUFBRSxFQUFFO01BQ1QsTUFBTSxJQUFJRSxLQUFLLENBQUMsMEJBQTBCUixHQUFHLENBQUNnQyxNQUFNLEVBQUUsQ0FBQztJQUMzRDtJQUVBLE1BQU03QixJQUFJLEdBQUcsTUFBTUgsR0FBRyxDQUFDNEMsSUFBSSxDQUFDLENBQUM7SUFDN0IsSUFBSSxDQUFDekMsSUFBSSxFQUFFO01BQ1AsTUFBTSxJQUFJSyxLQUFLLENBQUMsbUNBQW1DLENBQUM7SUFDeEQ7RUFDSjtFQUVPcUMsNEJBQTRCQSxDQUFDQyxJQUFVLEVBQUVDLE1BQWUsRUFBRUMsRUFBVyxFQUFVO0lBQ2xGLE1BQU1DLE1BQU0sR0FBR0gsSUFBSSxDQUFDRyxNQUFNO0lBQzFCLE1BQU1DLFFBQVEsR0FBR0osSUFBSSxDQUFDSyxJQUFJO0lBQzFCLElBQUl2RCxHQUFHLEdBQUcsSUFBSSxDQUFDakMsS0FBSztJQUNwQixJQUFJLElBQUksQ0FBQ0csV0FBVyxFQUFFOEIsR0FBRyxJQUFJLGdCQUFnQixHQUFHeUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDdkUsV0FBVyxDQUFDO0lBQ3BGOEIsR0FBRyxJQUFJLFdBQVcsR0FBR3lDLGtCQUFrQixDQUFDWSxNQUFNLENBQUM7SUFDL0NyRCxHQUFHLElBQUksYUFBYSxHQUFHeUMsa0JBQWtCLENBQUNhLFFBQVEsQ0FBQztJQUNuRHRELEdBQUcsSUFBSSxTQUFTLEdBQUd5QyxrQkFBa0IsQ0FBQ2Usc0JBQWEsQ0FBQ0MsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RFLElBQUlMLEVBQUUsRUFBRTtNQUNKcEQsR0FBRyxJQUFJLFlBQVksR0FBR3lDLGtCQUFrQixDQUFDVyxFQUFFLENBQUM7SUFDaEQ7SUFDQSxJQUFJRCxNQUFNLEVBQUU7TUFDUm5ELEdBQUcsSUFBSSxVQUFVLEdBQUd5QyxrQkFBa0IsQ0FBQ1UsTUFBTSxDQUFDO0lBQ2xEO0lBQ0EsT0FBT25ELEdBQUc7RUFDZDtFQUVPd0MsY0FBY0EsQ0FBQ2tCLGNBQXNCLEVBQVU7SUFDbEQsSUFBSSxDQUFDLElBQUksQ0FBQ3hGLFdBQVcsRUFBRSxPQUFPd0YsY0FBYztJQUM1QyxPQUFPQSxjQUFjLEdBQUcsZ0JBQWdCLEdBQUdqQixrQkFBa0IsQ0FBQyxJQUFJLENBQUN2RSxXQUFXLENBQUM7RUFDbkY7QUFDSjtBQUFDeUYsT0FBQSxDQUFBMUYsT0FBQSxHQUFBTCxnQkFBQSIsImlnbm9yZUxpc3QiOltdfQ==