matrix-react-sdk
Version:
SDK for matrix.org using React
487 lines (379 loc) • 57.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.StopGapWidget = exports.ElementWidget = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrixWidgetApi = require("matrix-widget-api");
var _StopGapWidgetDriver = require("./StopGapWidgetDriver");
var _events = require("events");
var _WidgetMessagingStore = require("./WidgetMessagingStore");
var _RoomViewStore = _interopRequireDefault(require("../RoomViewStore"));
var _MatrixClientPeg = require("../../MatrixClientPeg");
var _OwnProfileStore = require("../OwnProfileStore");
var _WidgetUtils = _interopRequireDefault(require("../../utils/WidgetUtils"));
var _IntegrationManagers = require("../../integrations/IntegrationManagers");
var _SettingsStore = _interopRequireDefault(require("../../settings/SettingsStore"));
var _WidgetType = require("../../widgets/WidgetType");
var _ActiveWidgetStore = _interopRequireDefault(require("../ActiveWidgetStore"));
var _objects = require("../../utils/objects");
var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher"));
var _ElementWidgetActions = require("./ElementWidgetActions");
var _ModalWidgetStore = require("../ModalWidgetStore");
var _ThemeWatcher = _interopRequireDefault(require("../../settings/watchers/ThemeWatcher"));
var _theme = require("../../theme");
var _CountlyAnalytics = _interopRequireDefault(require("../../CountlyAnalytics"));
var _ElementWidgetCapabilities = require("./ElementWidgetCapabilities");
var _identifiers = require("../../identifiers");
var _languageHandler = require("../../languageHandler");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
// TODO: Don't use this because it's wrong
class ElementWidget extends _matrixWidgetApi.Widget {
constructor(rawDefinition
/*: IWidget*/
) {
super(rawDefinition);
this.rawDefinition
/*:: */
= rawDefinition
/*:: */
;
}
get templateUrl()
/*: string*/
{
if (_WidgetType.WidgetType.JITSI.matches(this.type)) {
return _WidgetUtils.default.getLocalJitsiWrapperUrl({
forLocalRender: true,
auth: super.rawData?.auth // this.rawData can call templateUrl, do this to prevent looping
});
}
return super.templateUrl;
}
get popoutTemplateUrl()
/*: string*/
{
if (_WidgetType.WidgetType.JITSI.matches(this.type)) {
return _WidgetUtils.default.getLocalJitsiWrapperUrl({
forLocalRender: false,
// The only important difference between this and templateUrl()
auth: super.rawData?.auth
});
}
return this.templateUrl; // use this instead of super to ensure we get appropriate templating
}
get rawData()
/*: IWidgetData*/
{
let conferenceId = super.rawData['conferenceId'];
if (conferenceId === undefined) {
// we'll need to parse the conference ID out of the URL for v1 Jitsi widgets
const parsedUrl = new URL(super.templateUrl); // use super to get the raw widget URL
conferenceId = parsedUrl.searchParams.get("confId");
}
let domain = super.rawData['domain'];
if (domain === undefined) {
// v1 widgets default to jitsi.riot.im regardless of user settings
domain = "jitsi.riot.im";
}
let theme = new _ThemeWatcher.default().getEffectiveTheme();
if (theme.startsWith("custom-")) {
const customTheme = (0, _theme.getCustomTheme)(theme.substr(7)); // Jitsi only understands light/dark
theme = customTheme.is_dark ? "dark" : "light";
} // only allow light/dark through, defaulting to dark as that was previously the only state
// accounts for legacy-light/legacy-dark themes too
if (theme.includes("light")) {
theme = "light";
} else {
theme = "dark";
}
return _objectSpread(_objectSpread({}, super.rawData), {}, {
theme,
conferenceId,
domain
});
}
getCompleteUrl(params
/*: ITemplateParams*/
, asPopout = false)
/*: string*/
{
return (0, _matrixWidgetApi.runTemplate)(asPopout ? this.popoutTemplateUrl : this.templateUrl, _objectSpread(_objectSpread({}, this.rawDefinition), {}, {
data: this.rawData
}), params);
}
}
exports.ElementWidget = ElementWidget;
class StopGapWidget extends _events.EventEmitter {
constructor(appTileProps
/*: IAppTileProps*/
) {
super();
this.appTileProps
/*:: */
= appTileProps
/*:: */
;
(0, _defineProperty2.default)(this, "messaging", void 0);
(0, _defineProperty2.default)(this, "mockWidget", void 0);
(0, _defineProperty2.default)(this, "scalarToken", void 0);
(0, _defineProperty2.default)(this, "roomId", void 0);
(0, _defineProperty2.default)(this, "kind", void 0);
(0, _defineProperty2.default)(this, "onOpenModal", async (ev
/*: CustomEvent<IModalWidgetOpenRequest>*/
) => {
ev.preventDefault();
if (_ModalWidgetStore.ModalWidgetStore.instance.canOpenModalWidget()) {
_ModalWidgetStore.ModalWidgetStore.instance.openModalWidget(ev.detail.data, this.mockWidget);
this.messaging.transport.reply(ev.detail, {}); // ack
} else {
this.messaging.transport.reply(ev.detail, {
error: {
message: "Unable to open modal at this time"
}
});
}
});
(0, _defineProperty2.default)(this, "onEvent", (ev
/*: MatrixEvent*/
) => {
_MatrixClientPeg.MatrixClientPeg.get().decryptEventIfNeeded(ev);
if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) return;
if (ev.getRoomId() !== this.eventListenerRoomId) return;
this.feedEvent(ev);
});
(0, _defineProperty2.default)(this, "onEventDecrypted", (ev
/*: MatrixEvent*/
) => {
if (ev.isDecryptionFailure()) return;
if (ev.getRoomId() !== this.eventListenerRoomId) return;
this.feedEvent(ev);
});
let app = appTileProps.app; // Backwards compatibility: not all old widgets have a creatorUserId
if (!app.creatorUserId) {
app = (0, _objects.objectShallowClone)(app); // clone to prevent accidental mutation
app.creatorUserId = _MatrixClientPeg.MatrixClientPeg.get().getUserId();
}
this.mockWidget = new ElementWidget(app);
this.roomId = appTileProps.room?.roomId;
this.kind = appTileProps.userWidget ? _matrixWidgetApi.WidgetKind.Account : _matrixWidgetApi.WidgetKind.Room; // probably
}
get eventListenerRoomId()
/*: string*/
{
// When widgets are listening to events, we need to make sure they're only
// receiving events for the right room. In particular, room widgets get locked
// to the room they were added in while account widgets listen to the currently
// active room.
if (this.roomId) return this.roomId;
return _RoomViewStore.default.getRoomId();
}
get widgetApi()
/*: ClientWidgetApi*/
{
return this.messaging;
}
/**
* The URL to use in the iframe
*/
get embedUrl()
/*: string*/
{
return this.runUrlTemplate({
asPopout: false
});
}
/**
* The URL to use in the popout
*/
get popoutUrl()
/*: string*/
{
return this.runUrlTemplate({
asPopout: true
});
}
runUrlTemplate(opts = {
asPopout: false
})
/*: string*/
{
const templated = this.mockWidget.getCompleteUrl({
widgetRoomId: this.roomId,
currentUserId: _MatrixClientPeg.MatrixClientPeg.get().getUserId(),
userDisplayName: _OwnProfileStore.OwnProfileStore.instance.displayName,
userHttpAvatarUrl: _OwnProfileStore.OwnProfileStore.instance.getHttpAvatarUrl(),
clientId: _identifiers.ELEMENT_CLIENT_ID,
clientTheme: _SettingsStore.default.getValue("theme"),
clientLanguage: (0, _languageHandler.getUserLanguage)()
}, opts?.asPopout);
const parsed = new URL(templated); // Add in some legacy support sprinkles (for non-popout widgets)
// TODO: Replace these with proper widget params
// See https://github.com/matrix-org/matrix-doc/pull/1958/files#r405714833
if (!opts?.asPopout) {
parsed.searchParams.set('widgetId', this.mockWidget.id);
parsed.searchParams.set('parentUrl', window.location.href.split('#', 2)[0]); // Give the widget a scalar token if we're supposed to (more legacy)
// TODO: Stop doing this
if (this.scalarToken) {
parsed.searchParams.set('scalar_token', this.scalarToken);
}
} // Replace the encoded dollar signs back to dollar signs. They have no special meaning
// in HTTP, but URL parsers encode them anyways.
return parsed.toString().replace(/%24/g, '$');
}
get isManagedByManager()
/*: boolean*/
{
return !!this.scalarToken;
}
get started()
/*: boolean*/
{
return !!this.messaging;
}
get widgetId() {
return this.messaging.widget.id;
}
start(iframe
/*: HTMLIFrameElement*/
) {
if (this.started) return;
const allowedCapabilities = this.appTileProps.whitelistCapabilities || [];
const driver = new _StopGapWidgetDriver.StopGapWidgetDriver(allowedCapabilities, this.mockWidget, this.kind, this.roomId);
this.messaging = new _matrixWidgetApi.ClientWidgetApi(this.mockWidget, iframe, driver);
this.messaging.on("preparing", () => this.emit("preparing"));
this.messaging.on("ready", () => this.emit("ready"));
this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal);
_WidgetMessagingStore.WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging);
if (!this.appTileProps.userWidget && this.appTileProps.room) {
_ActiveWidgetStore.default.setRoomId(this.mockWidget.id, this.appTileProps.room.roomId);
} // Always attach a handler for ViewRoom, but permission check it internally
this.messaging.on(`action:${_ElementWidgetActions.ElementWidgetActions.ViewRoom}`, (ev
/*: CustomEvent<IViewRoomApiRequest>*/
) => {
ev.preventDefault(); // stop the widget API from auto-rejecting this
// Check up front if this is even a valid request
const targetRoomId = (ev.detail.data || {}).room_id;
if (!targetRoomId) {
return this.messaging.transport.reply(ev.detail, {
error: {
message: "Room ID not supplied."
}
});
} // Check the widget's permission
if (!this.messaging.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.CanChangeViewedRoom)) {
return this.messaging.transport.reply(ev.detail, {
error: {
message: "This widget does not have permission for this action (denied)."
}
});
} // at this point we can change rooms, so do that
_dispatcher.default.dispatch({
action: 'view_room',
room_id: targetRoomId
}); // acknowledge so the widget doesn't freak out
this.messaging.transport.reply(ev.detail, {});
}); // Attach listeners for feeding events - the underlying widget classes handle permissions for us
_MatrixClientPeg.MatrixClientPeg.get().on('event', this.onEvent);
_MatrixClientPeg.MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted);
this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.UpdateAlwaysOnScreen}`, (ev
/*: CustomEvent<IStickyActionRequest>*/
) => {
if (this.messaging.hasCapability(_matrixWidgetApi.MatrixCapabilities.AlwaysOnScreen)) {
if (_WidgetType.WidgetType.JITSI.matches(this.mockWidget.type)) {
_CountlyAnalytics.default.instance.trackJoinCall(this.appTileProps.room.roomId, true, true);
}
_ActiveWidgetStore.default.setWidgetPersistence(this.mockWidget.id, ev.detail.data.value);
ev.preventDefault();
this.messaging.transport.reply(ev.detail, {}); // ack
}
}); // TODO: Replace this event listener with appropriate driver functionality once the API
// establishes a sane way to send events back and forth.
this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.SendSticker}`, (ev
/*: CustomEvent<IStickerActionRequest>*/
) => {
if (this.messaging.hasCapability(_matrixWidgetApi.MatrixCapabilities.StickerSending)) {
// Acknowledge first
ev.preventDefault();
this.messaging.transport.reply(ev.detail, {}); // Send the sticker
_dispatcher.default.dispatch({
action: 'm.sticker',
data: ev.detail.data,
widgetId: this.mockWidget.id
});
}
});
if (_WidgetType.WidgetType.STICKERPICKER.matches(this.mockWidget.type)) {
this.messaging.on(`action:${_ElementWidgetActions.ElementWidgetActions.OpenIntegrationManager}`, (ev
/*: CustomEvent<IWidgetApiRequest>*/
) => {
// Acknowledge first
ev.preventDefault();
this.messaging.transport.reply(ev.detail, {}); // First close the stickerpicker
_dispatcher.default.dispatch({
action: "stickerpicker_close"
}); // Now open the integration manager
// TODO: Spec this interaction.
const data = ev.detail.data;
const integType = data?.integType;
const integId = data?.integId; // TODO: Open the right integration manager for the widget
if (_SettingsStore.default.getValue("feature_many_integration_managers")) {
_IntegrationManagers.IntegrationManagers.sharedInstance().openAll(_MatrixClientPeg.MatrixClientPeg.get().getRoom(_RoomViewStore.default.getRoomId()), `type_${integType}`, integId);
} else {
_IntegrationManagers.IntegrationManagers.sharedInstance().getPrimaryManager().open(_MatrixClientPeg.MatrixClientPeg.get().getRoom(_RoomViewStore.default.getRoomId()), `type_${integType}`, integId);
}
});
}
}
async prepare()
/*: Promise<void>*/
{
if (this.scalarToken) return;
const existingMessaging = _WidgetMessagingStore.WidgetMessagingStore.instance.getMessaging(this.mockWidget);
if (existingMessaging) this.messaging = existingMessaging;
try {
if (_WidgetUtils.default.isScalarUrl(this.mockWidget.templateUrl)) {
const managers = _IntegrationManagers.IntegrationManagers.sharedInstance();
if (managers.hasManager()) {
// TODO: Pick the right manager for the widget
const defaultManager = managers.getPrimaryManager();
if (_WidgetUtils.default.isScalarUrl(defaultManager.apiUrl)) {
const scalar = defaultManager.getScalarClient();
this.scalarToken = await scalar.getScalarToken();
}
}
}
} catch (e) {
// All errors are non-fatal
console.error("Error preparing widget communications: ", e);
}
}
stop(opts = {
forceDestroy: false
}) {
if (!opts?.forceDestroy && _ActiveWidgetStore.default.getPersistentWidgetId() === this.mockWidget.id) {
console.log("Skipping destroy - persistent widget");
return;
}
if (!this.started) return;
_WidgetMessagingStore.WidgetMessagingStore.instance.stopMessaging(this.mockWidget);
_ActiveWidgetStore.default.delRoomId(this.mockWidget.id);
if (_MatrixClientPeg.MatrixClientPeg.get()) {
_MatrixClientPeg.MatrixClientPeg.get().off('event', this.onEvent);
_MatrixClientPeg.MatrixClientPeg.get().off('Event.decrypted', this.onEventDecrypted);
}
}
feedEvent(ev
/*: MatrixEvent*/
) {
if (!this.messaging) return;
const raw = ev.event;
this.messaging.feedEvent(raw).catch(e => {
console.error("Error sending event to widget: ", e);
});
}
}
exports.StopGapWidget = StopGapWidget;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zdG9yZXMvd2lkZ2V0cy9TdG9wR2FwV2lkZ2V0LnRzIl0sIm5hbWVzIjpbIkVsZW1lbnRXaWRnZXQiLCJXaWRnZXQiLCJjb25zdHJ1Y3RvciIsInJhd0RlZmluaXRpb24iLCJ0ZW1wbGF0ZVVybCIsIldpZGdldFR5cGUiLCJKSVRTSSIsIm1hdGNoZXMiLCJ0eXBlIiwiV2lkZ2V0VXRpbHMiLCJnZXRMb2NhbEppdHNpV3JhcHBlclVybCIsImZvckxvY2FsUmVuZGVyIiwiYXV0aCIsInJhd0RhdGEiLCJwb3BvdXRUZW1wbGF0ZVVybCIsImNvbmZlcmVuY2VJZCIsInVuZGVmaW5lZCIsInBhcnNlZFVybCIsIlVSTCIsInNlYXJjaFBhcmFtcyIsImdldCIsImRvbWFpbiIsInRoZW1lIiwiVGhlbWVXYXRjaGVyIiwiZ2V0RWZmZWN0aXZlVGhlbWUiLCJzdGFydHNXaXRoIiwiY3VzdG9tVGhlbWUiLCJzdWJzdHIiLCJpc19kYXJrIiwiaW5jbHVkZXMiLCJnZXRDb21wbGV0ZVVybCIsInBhcmFtcyIsImFzUG9wb3V0IiwiZGF0YSIsIlN0b3BHYXBXaWRnZXQiLCJFdmVudEVtaXR0ZXIiLCJhcHBUaWxlUHJvcHMiLCJldiIsInByZXZlbnREZWZhdWx0IiwiTW9kYWxXaWRnZXRTdG9yZSIsImluc3RhbmNlIiwiY2FuT3Blbk1vZGFsV2lkZ2V0Iiwib3Blbk1vZGFsV2lkZ2V0IiwiZGV0YWlsIiwibW9ja1dpZGdldCIsIm1lc3NhZ2luZyIsInRyYW5zcG9ydCIsInJlcGx5IiwiZXJyb3IiLCJtZXNzYWdlIiwiTWF0cml4Q2xpZW50UGVnIiwiZGVjcnlwdEV2ZW50SWZOZWVkZWQiLCJpc0JlaW5nRGVjcnlwdGVkIiwiaXNEZWNyeXB0aW9uRmFpbHVyZSIsImdldFJvb21JZCIsImV2ZW50TGlzdGVuZXJSb29tSWQiLCJmZWVkRXZlbnQiLCJhcHAiLCJjcmVhdG9yVXNlcklkIiwiZ2V0VXNlcklkIiwicm9vbUlkIiwicm9vbSIsImtpbmQiLCJ1c2VyV2lkZ2V0IiwiV2lkZ2V0S2luZCIsIkFjY291bnQiLCJSb29tIiwiUm9vbVZpZXdTdG9yZSIsIndpZGdldEFwaSIsImVtYmVkVXJsIiwicnVuVXJsVGVtcGxhdGUiLCJwb3BvdXRVcmwiLCJvcHRzIiwidGVtcGxhdGVkIiwid2lkZ2V0Um9vbUlkIiwiY3VycmVudFVzZXJJZCIsInVzZXJEaXNwbGF5TmFtZSIsIk93blByb2ZpbGVTdG9yZSIsImRpc3BsYXlOYW1lIiwidXNlckh0dHBBdmF0YXJVcmwiLCJnZXRIdHRwQXZhdGFyVXJsIiwiY2xpZW50SWQiLCJFTEVNRU5UX0NMSUVOVF9JRCIsImNsaWVudFRoZW1lIiwiU2V0dGluZ3NTdG9yZSIsImdldFZhbHVlIiwiY2xpZW50TGFuZ3VhZ2UiLCJwYXJzZWQiLCJzZXQiLCJpZCIsIndpbmRvdyIsImxvY2F0aW9uIiwiaHJlZiIsInNwbGl0Iiwic2NhbGFyVG9rZW4iLCJ0b1N0cmluZyIsInJlcGxhY2UiLCJpc01hbmFnZWRCeU1hbmFnZXIiLCJzdGFydGVkIiwid2lkZ2V0SWQiLCJ3aWRnZXQiLCJzdGFydCIsImlmcmFtZSIsImFsbG93ZWRDYXBhYmlsaXRpZXMiLCJ3aGl0ZWxpc3RDYXBhYmlsaXRpZXMiLCJkcml2ZXIiLCJTdG9wR2FwV2lkZ2V0RHJpdmVyIiwiQ2xpZW50V2lkZ2V0QXBpIiwib24iLCJlbWl0IiwiV2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbiIsIk9wZW5Nb2RhbFdpZGdldCIsIm9uT3Blbk1vZGFsIiwiV2lkZ2V0TWVzc2FnaW5nU3RvcmUiLCJzdG9yZU1lc3NhZ2luZyIsIkFjdGl2ZVdpZGdldFN0b3JlIiwic2V0Um9vbUlkIiwiRWxlbWVudFdpZGdldEFjdGlvbnMiLCJWaWV3Um9vbSIsInRhcmdldFJvb21JZCIsInJvb21faWQiLCJoYXNDYXBhYmlsaXR5IiwiRWxlbWVudFdpZGdldENhcGFiaWxpdGllcyIsIkNhbkNoYW5nZVZpZXdlZFJvb20iLCJkZWZhdWx0RGlzcGF0Y2hlciIsImRpc3BhdGNoIiwiYWN0aW9uIiwib25FdmVudCIsIm9uRXZlbnREZWNyeXB0ZWQiLCJVcGRhdGVBbHdheXNPblNjcmVlbiIsIk1hdHJpeENhcGFiaWxpdGllcyIsIkFsd2F5c09uU2NyZWVuIiwiQ291bnRseUFuYWx5dGljcyIsInRyYWNrSm9pbkNhbGwiLCJzZXRXaWRnZXRQZXJzaXN0ZW5jZSIsInZhbHVlIiwiU2VuZFN0aWNrZXIiLCJTdGlja2VyU2VuZGluZyIsIlNUSUNLRVJQSUNLRVIiLCJPcGVuSW50ZWdyYXRpb25NYW5hZ2VyIiwiaW50ZWdUeXBlIiwiaW50ZWdJZCIsIkludGVncmF0aW9uTWFuYWdlcnMiLCJzaGFyZWRJbnN0YW5jZSIsIm9wZW5BbGwiLCJnZXRSb29tIiwiZ2V0UHJpbWFyeU1hbmFnZXIiLCJvcGVuIiwicHJlcGFyZSIsImV4aXN0aW5nTWVzc2FnaW5nIiwiZ2V0TWVzc2FnaW5nIiwiaXNTY2FsYXJVcmwiLCJtYW5hZ2VycyIsImhhc01hbmFnZXIiLCJkZWZhdWx0TWFuYWdlciIsImFwaVVybCIsInNjYWxhciIsImdldFNjYWxhckNsaWVudCIsImdldFNjYWxhclRva2VuIiwiZSIsImNvbnNvbGUiLCJzdG9wIiwiZm9yY2VEZXN0cm95IiwiZ2V0UGVyc2lzdGVudFdpZGdldElkIiwibG9nIiwic3RvcE1lc3NhZ2luZyIsImRlbFJvb21JZCIsIm9mZiIsInJhdyIsImV2ZW50IiwiY2F0Y2giXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBaUJBOztBQWlCQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7Ozs7O0FBZ0JBO0FBQ08sTUFBTUEsYUFBTixTQUE0QkMsdUJBQTVCLENBQW1DO0FBQ3RDQyxFQUFBQSxXQUFXLENBQVNDO0FBQVQ7QUFBQSxJQUFpQztBQUN4QyxVQUFNQSxhQUFOO0FBRHdDLFNBQXhCQTtBQUF3QjtBQUFBLE1BQXhCQTtB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QUFMLENBQWVXLFNBQWYsQ0FBeUJnSCxHQUF6QixFQUE4QkUsS0FBOUIsQ0FBb0NYLENBQUMsSUFBSTtBQUNyQ0MsTUFBQUEsT0FBTyxDQUFDaEgsS0FBUixDQUFjLGlDQUFkLEVBQWlEK0csQ0FBakQ7QUFDSCxLQUZEO0FBR0g7O0FBeFIyQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAyMCwgMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgUm9vbSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvcm9vbVwiO1xuaW1wb3J0IHtcbiAgICBDbGllbnRXaWRnZXRBcGksXG4gICAgSVN0aWNrZXJBY3Rpb25SZXF1ZXN0LFxuICAgIElTdGlja3lBY3Rpb25SZXF1ZXN0LFxuICAgIElUZW1wbGF0ZVBhcmFtcyxcbiAgICBJV2lkZ2V0LFxuICAgIElXaWRnZXRBcGlSZXF1ZXN0LFxuICAgIElXaWRnZXRBcGlSZXF1ZXN0RW1wdHlEYXRhLFxuICAgIElXaWRnZXREYXRhLFxuICAgIE1hdHJpeENhcGFiaWxpdGllcyxcbiAgICBydW5UZW1wbGF0ZSxcbiAgICBXaWRnZXQsXG4gICAgV2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbixcbiAgICBJTW9kYWxXaWRnZXRPcGVuUmVxdWVzdCxcbiAgICBJV2lkZ2V0QXBpRXJyb3JSZXNwb25zZURhdGEsXG4gICAgV2lkZ2V0S2luZCxcbn0gZnJvbSBcIm1hdHJpeC13aWRnZXQtYXBpXCI7XG5pbXBvcnQgeyBTdG9wR2FwV2lkZ2V0RHJpdmVyIH0gZnJvbSBcIi4vU3RvcEdhcFdpZGdldERyaXZlclwiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiO1xuaW1wb3J0IHsgV2lkZ2V0TWVzc2FnaW5nU3RvcmUgfSBmcm9tIFwiLi9XaWRnZXRNZXNzYWdpbmdTdG9yZVwiO1xuaW1wb3J0IFJvb21WaWV3U3RvcmUgZnJvbSBcIi4uL1Jvb21WaWV3U3RvcmVcIjtcbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuLi8uLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IE93blByb2ZpbGVTdG9yZSB9IGZyb20gXCIuLi9Pd25Qcm9maWxlU3RvcmVcIjtcbmltcG9ydCBXaWRnZXRVdGlscyBmcm9tICcuLi8uLi91dGlscy9XaWRnZXRVdGlscyc7XG5pbXBvcnQgeyBJbnRlZ3JhdGlvbk1hbmFnZXJzIH0gZnJvbSBcIi4uLy4uL2ludGVncmF0aW9ucy9JbnRlZ3JhdGlvbk1hbmFnZXJzXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IHsgV2lkZ2V0VHlwZSB9IGZyb20gXCIuLi8uLi93aWRnZXRzL1dpZGdldFR5cGVcIjtcbmltcG9ydCBBY3RpdmVXaWRnZXRTdG9yZSBmcm9tIFwiLi4vQWN0aXZlV2lkZ2V0U3RvcmVcIjtcbmltcG9ydCB7IG9iamVjdFNoYWxsb3dDbG9uZSB9IGZyb20gXCIuLi8uLi91dGlscy9vYmplY3RzXCI7XG5pbXBvcnQgZGVmYXVsdERpc3BhdGNoZXIgZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgRWxlbWVudFdpZGdldEFjdGlvbnMsIElWaWV3Um9vbUFwaVJlcXVlc3QgfSBmcm9tIFwiLi9FbGVtZW50V2lkZ2V0QWN0aW9uc1wiO1xuaW1wb3J0IHtNb2RhbFdpZGdldFN0b3JlfSBmcm9tIFwiLi4vTW9kYWxXaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFRoZW1lV2F0Y2hlciBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvd2F0Y2hlcnMvVGhlbWVXYXRjaGVyXCI7XG5pbXBvcnQge2dldEN1c3RvbVRoZW1lfSBmcm9tIFwiLi4vLi4vdGhlbWVcIjtcbmltcG9ydCBDb3VudGx5QW5hbHl0aWNzIGZyb20gXCIuLi8uLi9Db3VudGx5QW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBFbGVtZW50V2lkZ2V0Q2FwYWJpbGl0aWVzIH0gZnJvbSBcIi4vRWxlbWVudFdpZGdldENhcGFiaWxpdGllc1wiO1xuaW1wb3J0IHsgTWF0cml4RXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbW9kZWxzL2V2ZW50XCI7XG5pbXBvcnQgeyBFTEVNRU5UX0NMSUVOVF9JRCB9IGZyb20gXCIuLi8uLi9pZGVudGlmaWVyc1wiO1xuaW1wb3J0IHsgZ2V0VXNlckxhbmd1YWdlIH0gZnJvbSBcIi4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuXG4vLyBUT0RPOiBEZXN0cm95IGFsbCBvZiB0aGlzIGNvZGVcblxuaW50ZXJmYWNlIElBcHBUaWxlUHJvcHMge1xuICAgIC8vIE5vdGU6IHRoZXNlIGFyZSBvbmx5IHRoZSBwcm9wcyB3ZSBjYXJlIGFib3V0XG5cbiAgICBhcHA6IElXaWRnZXQ7XG4gICAgcm9vbTogUm9vbTtcbiAgICB1c2VySWQ6IHN0cmluZztcbiAgICBjcmVhdG9yVXNlcklkOiBzdHJpbmc7XG4gICAgd2FpdEZvcklmcmFtZUxvYWQ6IGJvb2xlYW47XG4gICAgd2hpdGVsaXN0Q2FwYWJpbGl0aWVzOiBzdHJpbmdbXTtcbiAgICB1c2VyV2lkZ2V0OiBib29sZWFuO1xufVxuXG4vLyBUT0RPOiBEb24ndCB1c2UgdGhpcyBiZWNhdXNlIGl0J3Mgd3JvbmdcbmV4cG9ydCBjbGFzcyBFbGVtZW50V2lkZ2V0IGV4dGVuZHMgV2lkZ2V0IHtcbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJhd0RlZmluaXRpb246IElXaWRnZXQpIHtcbiAgICAgICAgc3VwZXIocmF3RGVmaW5pdGlvbik7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0ZW1wbGF0ZVVybCgpOiBzdHJpbmcge1xuICAgICAgICBpZiAoV2lkZ2V0VHlwZS5KSVRTSS5tYXRjaGVzKHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBXaWRnZXRVdGlscy5nZXRMb2NhbEppdHNpV3JhcHBlclVybCh7XG4gICAgICAgICAgICAgICAgZm9yTG9jYWxSZW5kZXI6IHRydWUsXG4gICAgICAgICAgICAgICAgYXV0aDogc3VwZXIucmF3RGF0YT8uYXV0aCBhcyBzdHJpbmcsIC8vIHRoaXMucmF3RGF0YSBjYW4gY2FsbCB0ZW1wbGF0ZVVybCwgZG8gdGhpcyB0byBwcmV2ZW50IGxvb3BpbmdcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdXBlci50ZW1wbGF0ZVVybDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHBvcG91dFRlbXBsYXRlVXJsKCk6IHN0cmluZyB7XG4gICAgICAgIGlmIChXaWRnZXRUeXBlLkpJVFNJLm1hdGNoZXModGhpcy50eXBlKSkge1xuICAgICAgICAgICAgcmV0dXJuIFdpZGdldFV0aWxzLmdldExvY2FsSml0c2lXcmFwcGVyVXJsKHtcbiAgICAgICAgICAgICAgICBmb3JMb2NhbFJlbmRlcjogZmFsc2UsIC8vIFRoZSBvbmx5IGltcG9ydGFudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhpcyBhbmQgdGVtcGxhdGVVcmwoKVxuICAgICAgICAgICAgICAgIGF1dGg6IHN1cGVyLnJhd0RhdGE/LmF1dGggYXMgc3RyaW5nLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMudGVtcGxhdGVVcmw7IC8vIHVzZSB0aGlzIGluc3RlYWQgb2Ygc3VwZXIgdG8gZW5zdXJlIHdlIGdldCBhcHByb3ByaWF0ZSB0ZW1wbGF0aW5nXG4gICAgfVxuXG4gICAgcHVibGljIGdldCByYXdEYXRhKCk6IElXaWRnZXREYXRhIHtcbiAgICAgICAgbGV0IGNvbmZlcmVuY2VJZCA9IHN1cGVyLnJhd0RhdGFbJ2NvbmZlcmVuY2VJZCddO1xuICAgICAgICBpZiAoY29uZmVyZW5jZUlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHdlJ2xsIG5lZWQgdG8gcGFyc2UgdGhlIGNvbmZlcmVuY2UgSUQgb3V0IG9mIHRoZSBVUkwgZm9yIHYxIEppdHNpIHdpZGdldHNcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZFVybCA9IG5ldyBVUkwoc3VwZXIudGVtcGxhdGVVcmwpOyAvLyB1c2Ugc3VwZXIgdG8gZ2V0IHRoZSByYXcgd2lkZ2V0IFVSTFxuICAgICAgICAgICAgY29uZmVyZW5jZUlkID0gcGFyc2VkVXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJjb25mSWRcIik7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGRvbWFpbiA9IHN1cGVyLnJhd0RhdGFbJ2RvbWFpbiddO1xuICAgICAgICBpZiAoZG9tYWluID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHYxIHdpZGdldHMgZGVmYXVsdCB0byBqaXRzaS5yaW90LmltIHJlZ2FyZGxlc3Mgb2YgdXNlciBzZXR0aW5nc1xuICAgICAgICAgICAgZG9tYWluID0gXCJqaXRzaS5yaW90LmltXCI7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdGhlbWUgPSBuZXcgVGhlbWVXYXRjaGVyKCkuZ2V0RWZmZWN0aXZlVGhlbWUoKTtcbiAgICAgICAgaWYgKHRoZW1lLnN0YXJ0c1dpdGgoXCJjdXN0b20tXCIpKSB7XG4gICAgICAgICAgICBjb25zdCBjdXN0b21UaGVtZSA9IGdldEN1c3RvbVRoZW1lKHRoZW1lLnN1YnN0cig3KSk7XG4gICAgICAgICAgICAvLyBKaXRzaSBvbmx5IHVuZGVyc3RhbmRzIGxpZ2h0L2RhcmtcbiAgICAgICAgICAgIHRoZW1lID0gY3VzdG9tVGhlbWUuaXNfZGFyayA/IFwiZGFya1wiIDogXCJsaWdodFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gb25seSBhbGxvdyBsaWdodC9kYXJrIHRocm91Z2gsIGRlZmF1bHRpbmcgdG8gZGFyayBhcyB0aGF0IHdhcyBwcmV2aW91c2x5IHRoZSBvbmx5IHN0YXRlXG4gICAgICAgIC8vIGFjY291bnRzIGZvciBsZWdhY3ktbGlnaHQvbGVnYWN5LWRhcmsgdGhlbWVzIHRvb1xuICAgICAgICBpZiAodGhlbWUuaW5jbHVkZXMoXCJsaWdodFwiKSkge1xuICAgICAgICAgICAgdGhlbWUgPSBcImxpZ2h0XCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGVtZSA9IFwiZGFya1wiO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLnN1cGVyLnJhd0RhdGEsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIGNvbmZlcmVuY2VJZCxcbiAgICAgICAgICAgIGRvbWFpbixcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q29tcGxldGVVcmwocGFyYW1zOiBJVGVtcGxhdGVQYXJhbXMsIGFzUG9wb3V0PWZhbHNlKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHJ1blRlbXBsYXRlKGFzUG9wb3V0ID8gdGhpcy5wb3BvdXRUZW1wbGF0ZVVybCA6IHRoaXMudGVtcGxhdGVVcmwsIHtcbiAgICAgICAgICAgIC4uLnRoaXMucmF3RGVmaW5pdGlvbixcbiAgICAgICAgICAgIGRhdGE6IHRoaXMucmF3RGF0YSxcbiAgICAgICAgfSwgcGFyYW1zKTtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBTdG9wR2FwV2lkZ2V0IGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBwcml2YXRlIG1lc3NhZ2luZzogQ2xpZW50V2lkZ2V0QXBpO1xuICAgIHByaXZhdGUgbW9ja1dpZGdldDogRWxlbWVudFdpZGdldDtcbiAgICBwcml2YXRlIHNjYWxhclRva2VuOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByb29tSWQ/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBraW5kOiBXaWRnZXRLaW5kO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBhcHBUaWxlUHJvcHM6IElBcHBUaWxlUHJvcHMpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgbGV0IGFwcCA9IGFwcFRpbGVQcm9wcy5hcHA7XG5cbiAgICAgICAgLy8gQmFja3dhcmRzIGNvbXBhdGliaWxpdHk6IG5vdCBhbGwgb2xkIHdpZGdldHMgaGF2ZSBhIGNyZWF0b3JVc2VySWRcbiAgICAgICAgaWYgKCFhcHAuY3JlYXRvclVzZXJJZCkge1xuICAgICAgICAgICAgYXBwID0gb2JqZWN0U2hhbGxvd0Nsb25lKGFwcCk7IC8vIGNsb25lIHRvIHByZXZlbnQgYWNjaWRlbnRhbCBtdXRhdGlvblxuICAgICAgICAgICAgYXBwLmNyZWF0b3JVc2VySWQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0VXNlcklkKCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1vY2tXaWRnZXQgPSBuZXcgRWxlbWVudFdpZGdldChhcHApO1xuICAgICAgICB0aGlzLnJvb21JZCA9IGFwcFRpbGVQcm9wcy5yb29tPy5yb29tSWQ7XG4gICAgICAgIHRoaXMua2luZCA9IGFwcFRpbGVQcm9wcy51c2VyV2lkZ2V0ID8gV2lkZ2V0S2luZC5BY2NvdW50IDogV2lkZ2V0S2luZC5Sb29tOyAvLyBwcm9iYWJseVxuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGV2ZW50TGlzdGVuZXJSb29tSWQoKTogc3RyaW5nIHtcbiAgICAgICAgLy8gV2hlbiB3aWRnZXRzIGFyZSBsaXN0ZW5pbmcgdG8gZXZlbnRzLCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB0aGV5J3JlIG9ubHlcbiAgICAgICAgLy8gcmVjZWl2aW5nIGV2ZW50cyBmb3IgdGhlIHJpZ2h0IHJvb20uIEluIHBhcnRpY3VsYXIsIHJvb20gd2lkZ2V0cyBnZXQgbG9ja2VkXG4gICAgICAgIC8vIHRvIHRoZSByb29tIHRoZXkgd2VyZSBhZGRlZCBpbiB3aGlsZSBhY2NvdW50IHdpZGdldHMgbGlzdGVuIHRvIHRoZSBjdXJyZW50bHlcbiAgICAgICAgLy8gYWN0aXZlIHJvb20uXG5cbiAgICAgICAgaWYgKHRoaXMucm9vbUlkKSByZXR1cm4gdGhpcy5yb29tSWQ7XG5cbiAgICAgICAgcmV0dXJuIFJvb21WaWV3U3RvcmUuZ2V0Um9vbUlkKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB3aWRnZXRBcGkoKTogQ2xpZW50V2lkZ2V0QXBpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBVUkwgdG8gdXNlIGluIHRoZSBpZnJhbWVcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGVtYmVkVXJsKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blVybFRlbXBsYXRlKHthc1BvcG91dDogZmFsc2V9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgVVJMIHRvIHVzZSBpbiB0aGUgcG9wb3V0XG4gICAgICovXG4gICAgcHVibGljIGdldCBwb3BvdXRVcmwoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuVXJsVGVtcGxhdGUoe2FzUG9wb3V0OiB0cnVlfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBydW5VcmxUZW1wbGF0ZShvcHRzID0ge2FzUG9wb3V0OiBmYWxzZX0pOiBzdHJpbmcge1xuICAgICAgICBjb25zdCB0ZW1wbGF0ZWQgPSB0aGlzLm1vY2tXaWRnZXQuZ2V0Q29tcGxldGVVcmwoe1xuICAgICAgICAgICAgd2lkZ2V0Um9vbUlkOiB0aGlzLnJvb21JZCxcbiAgICAgICAgICAgIGN1cnJlbnRVc2VySWQ6IE1hdHJpeENsaWVudFBlZy5nZXQoKS5nZXRVc2VySWQoKSxcbiAgICAgICAgICAgIHVzZXJEaXNwbGF5TmFtZTogT3duUHJvZmlsZVN0b3JlLmluc3RhbmNlLmRpc3BsYXlOYW1lLFxuICAgICAgICAgICAgdXNlckh0dHBBdmF0YXJVcmw6IE93blByb2ZpbGVTdG9yZS5pbnN0YW5jZS5nZXRIdHRwQXZhdGFyVXJsKCksXG4gICAgICAgICAgICBjbGllbnRJZDogRUxFTUVOVF9DTElFTlRfSUQsXG4gICAgICAgICAgICBjbGllbnRUaGVtZTogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInRoZW1lXCIpLFxuICAgICAgICAgICAgY2xpZW50TGFuZ3VhZ2U6IGdldFVzZXJMYW5ndWFnZSgpLFxuICAgICAgICB9LCBvcHRzPy5hc1BvcG91dCk7XG5cbiAgICAgICAgY29uc3QgcGFyc2VkID0gbmV3IFVSTCh0ZW1wbGF0ZWQpO1xuXG4gICAgICAgIC8vIEFkZCBpbiBzb21lIGxlZ2FjeSBzdXBwb3J0IHNwcmlua2xlcyAoZm9yIG5vbi1wb3BvdXQgd2lkZ2V0cylcbiAgICAgICAgLy8gVE9ETzogUmVwbGFjZSB0aGVzZSB3aXRoIHByb3BlciB3aWRnZXQgcGFyYW1zXG4gICAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vbWF0cml4LW9yZy9tYXRyaXgtZG9jL3B1bGwvMTk1OC9maWxlcyNyNDA1NzE0ODMzXG4gICAgICAgIGlmICghb3B0cz8uYXNQb3BvdXQpIHtcbiAgICAgICAgICAgIHBhcnNlZC5zZWFyY2hQYXJhbXMuc2V0KCd3aWRnZXRJZCcsIHRoaXMubW9ja1dpZGdldC5pZCk7XG4gICAgICAgICAgICBwYXJzZWQuc2VhcmNoUGFyYW1zLnNldCgncGFyZW50VXJsJywgd2luZG93LmxvY2F0aW9uLmhyZWYuc3BsaXQoJyMnLCAyKVswXSk7XG5cbiAgICAgICAgICAgIC8vIEdpdmUgdGhlIHdpZGdldCBhIHNjYWxhciB0b2tlbiBpZiB3ZSdyZSBzdXBwb3NlZCB0byAobW9yZSBsZWdhY3kpXG4gICAgICAgICAgICAvLyBUT0RPOiBTdG9wIGRvaW5nIHRoaXNcbiAgICAgICAgICAgIGlmICh0aGlzLnNjYWxhclRva2VuKSB7XG4gICAgICAgICAgICAgICAgcGFyc2VkLnNlYXJjaFBhcmFtcy5zZXQoJ3NjYWxhcl90b2tlbicsIHRoaXMuc2NhbGFyVG9rZW4pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVwbGFjZSB0aGUgZW5jb2RlZCBkb2xsYXIgc2lnbnMgYmFjayB0byBkb2xsYXIgc2lnbnMuIFRoZXkgaGF2ZSBubyBzcGVjaWFsIG1lYW5pbmdcbiAgICAgICAgLy8gaW4gSFRUUCwgYnV0IFVSTCBwYXJzZXJzIGVuY29kZSB0aGVtIGFueXdheXMuXG4gICAgICAgIHJldHVybiBwYXJzZWQudG9TdHJpbmcoKS5yZXBsYWNlKC8lMjQvZywgJyQnKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGlzTWFuYWdlZEJ5TWFuYWdlcigpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5zY2FsYXJUb2tlbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHN0YXJ0ZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMubWVzc2FnaW5nO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IHdpZGdldElkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tZXNzYWdpbmcud2lkZ2V0LmlkO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25PcGVuTW9kYWwgPSBhc3luYyAoZXY6IEN1c3RvbUV2ZW50PElNb2RhbFdpZGdldE9wZW5SZXF1ZXN0PikgPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBpZiAoTW9kYWxXaWRnZXRTdG9yZS5pbnN0YW5jZS5jYW5PcGVuTW9kYWxXaWRnZXQoKSkge1xuICAgICAgICAgICAgTW9kYWxXaWRnZXRTdG9yZS5pbnN0YW5jZS5vcGVuTW9kYWxXaWRnZXQoZXYuZGV0YWlsLmRhdGEsIHRoaXMubW9ja1dpZGdldCk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy50cmFuc3BvcnQucmVwbHkoZXYuZGV0YWlsLCB7fSk7IC8vIGFja1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwge1xuICAgICAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IFwiVW5hYmxlIHRvIG9wZW4gbW9kYWwgYXQgdGhpcyB0aW1lXCIsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHVibGljIHN0YXJ0KGlmcmFtZTogSFRNTElGcmFtZUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhcnRlZCkgcmV0dXJuO1xuICAgICAgICBjb25zdCBhbGxvd2VkQ2FwYWJpbGl0aWVzID0gdGhpcy5hcHBUaWxlUHJvcHMud2hpdGVsaXN0Q2FwYWJpbGl0aWVzIHx8IFtdO1xuICAgICAgICBjb25zdCBkcml2ZXIgPSBuZXcgU3RvcEdhcFdpZGdldERyaXZlcihhbGxvd2VkQ2FwYWJpbGl0aWVzLCB0aGlzLm1vY2tXaWRnZXQsIHRoaXMua2luZCwgdGhpcy5yb29tSWQpO1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IG5ldyBDbGllbnRXaWRnZXRBcGkodGhpcy5tb2NrV2lkZ2V0LCBpZnJhbWUsIGRyaXZlcik7XG4gICAgICAgIHRoaXMubWVzc2FnaW5nLm9uKFwicHJlcGFyaW5nXCIsICgpID0+IHRoaXMuZW1pdChcInByZXBhcmluZ1wiKSk7XG4gICAgICAgIHRoaXMubWVzc2FnaW5nLm9uKFwicmVhZHlcIiwgKCkgPT4gdGhpcy5lbWl0KFwicmVhZHlcIikpO1xuICAgICAgICB0aGlzLm1lc3NhZ2luZy5vbihgYWN0aW9uOiR7V2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbi5PcGVuTW9kYWxXaWRnZXR9YCwgdGhpcy5vbk9wZW5Nb2RhbCk7XG4gICAgICAgIFdpZGdldE1lc3NhZ2luZ1N0b3JlLmluc3RhbmNlLnN0b3JlTWVzc2FnaW5nKHRoaXMubW9ja1dpZGdldCwgdGhpcy5tZXNzYWdpbmcpO1xuXG4gICAgICAgIGlmICghdGhpcy5hcHBUaWxlUHJvcHMudXNlcldpZGdldCAmJiB0aGlzLmFwcFRpbGVQcm9wcy5yb29tKSB7XG4gICAgICAgICAgICBBY3RpdmVXaWRnZXRTdG9yZS5zZXRSb29tSWQodGhpcy5tb2NrV2lkZ2V0LmlkLCB0aGlzLmFwcFRpbGVQcm9wcy5yb29tLnJvb21JZCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBbHdheXMgYXR0YWNoIGEgaGFuZGxlciBmb3IgVmlld1Jvb20sIGJ1dCBwZXJtaXNzaW9uIGNoZWNrIGl0IGludGVybmFsbHlcbiAgICAgICAgdGhpcy5tZXNzYWdpbmcub24oYGFjdGlvbjoke0VsZW1lbnRXaWRnZXRBY3Rpb25zLlZpZXdSb29tfWAsIChldjogQ3VzdG9tRXZlbnQ8SVZpZXdSb29tQXBpUmVxdWVzdD4pID0+IHtcbiAgICAgICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7IC8vIHN0b3AgdGhlIHdpZGdldCBBUEkgZnJvbSBhdXRvLXJlamVjdGluZyB0aGlzXG5cbiAgICAgICAgICAgIC8vIENoZWNrIHVwIGZyb250IGlmIHRoaXMgaXMgZXZlbiBhIHZhbGlkIHJlcXVlc3RcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldFJvb21JZCA9IChldi5kZXRhaWwuZGF0YSB8fCB7fSkucm9vbV9pZDtcbiAgICAgICAgICAgIGlmICghdGFyZ2V0Um9vbUlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnaW5nLnRyYW5zcG9ydC5yZXBseShldi5kZXRhaWwsIDxJV2lkZ2V0QXBpRXJyb3JSZXNwb25zZURhdGE+e1xuICAgICAgICAgICAgICAgICAgICBlcnJvcjoge21lc3NhZ2U6IFwiUm9vbSBJRCBub3Qgc3VwcGxpZWQuXCJ9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgd2lkZ2V0J3MgcGVybWlzc2lvblxuICAgICAgICAgICAgaWYgKCF0aGlzLm1lc3NhZ2luZy5oYXNDYXBhYmlsaXR5KEVsZW1lbnRXaWRnZXRDYXBhYmlsaXRpZXMuQ2FuQ2hhbmdlVmlld2VkUm9vbSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwgPElXaWRnZXRBcGlFcnJvclJlc3BvbnNlRGF0YT57XG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiB7bWVzc2FnZTogXCJUaGlzIHdpZGdldCBkb2VzIG5vdCBoYXZlIHBlcm1pc3Npb24gZm9yIHRoaXMgYWN0aW9uIChkZW5pZWQpLlwifSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gYXQgdGhpcyBwb2ludCB3ZSBjYW4gY2hhbmdlIHJvb21zLCBzbyBkbyB0aGF0XG4gICAgICAgICAgICBkZWZhdWx0RGlzcGF0Y2hlci5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgYWN0aW9uOiAndmlld19yb29tJyxcbiAgICAgICAgICAgICAgICByb29tX2lkOiB0YXJnZXRSb29tSWQsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gYWNrbm93bGVkZ2Ugc28gdGhlIHdpZGdldCBkb2Vzbid0IGZyZWFrIG91dFxuICAgICAgICAgICAgdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwgPElXaWRnZXRBcGlSZXF1ZXN0RW1wdHlEYXRhPnt9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQXR0YWNoIGxpc3RlbmVycyBmb3IgZmVlZGluZyBldmVudHMgLSB0aGUgdW5kZXJseWluZyB3aWRnZXQgY2xhc3NlcyBoYW5kbGUgcGVybWlzc2lvbnMgZm9yIHVzXG4gICAgICAgIE1hdHJpeENsaWVudFBlZy5nZXQoKS5vbignZXZlbnQnLCB0aGlzLm9uRXZlbnQpO1xuICAgICAgICBNYXRyaXhDbGllbnRQZWcuZ2V0KCkub24oJ0V2ZW50LmRlY3J5cHRlZCcsIHRoaXMub25FdmVudERlY3J5cHRlZCk7XG5cbiAgICAgICAgdGhpcy5tZXNzYWdpbmcub24oYGFjdGlvbjoke1dpZGdldEFwaUZyb21XaWRnZXRBY3Rpb24uVXBkYXRlQWx3YXlzT25TY3JlZW59YCxcbiAgICAgICAgICAgIChldjogQ3VzdG9tRXZlbnQ8SVN0aWNreUFjdGlvblJlcXVlc3Q+KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWVzc2FnaW5nLmhhc0NhcGFiaWxpdHkoTWF0cml4Q2FwYWJpbGl0aWVzLkFsd2F5c09uU2NyZWVuKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoV2lkZ2V0VHlwZS5KSVRTSS5tYXRjaGVzKHRoaXMubW9ja1dpZGdldC50eXBlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgQ291bnRseUFuYWx5dGljcy5pbnN0YW5jZS50cmFja0pvaW5