matrix-react-sdk
Version:
SDK for matrix.org using React
208 lines (203 loc) • 35.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.OwnDevicesError = void 0;
exports.fetchExtendedDeviceInformation = fetchExtendedDeviceInformation;
exports.useOwnDevices = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = require("react");
var _matrix = require("matrix-js-sdk/src/matrix");
var _logger = require("matrix-js-sdk/src/logger");
var _crypto = require("matrix-js-sdk/src/crypto");
var _languageHandler = require("../../../../languageHandler");
var _clientInformation = require("../../../../utils/device/clientInformation");
var _useEventEmitter = require("../../../../hooks/useEventEmitter");
var _parseUserAgent = require("../../../../utils/device/parseUserAgent");
var _isDeviceVerified = require("../../../../utils/device/isDeviceVerified");
var _SDKContext = require("../../../../contexts/SDKContext");
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /*
Copyright 2024 New Vector Ltd.
Copyright 2022 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.
*/
const parseDeviceExtendedInformation = (matrixClient, device) => {
const {
name,
version,
url
} = (0, _clientInformation.getDeviceClientInformation)(matrixClient, device.device_id);
return {
appName: name,
appVersion: version,
url
};
};
/**
* Fetch extended details of the user's own devices
*
* @param matrixClient - Matrix Client
* @returns A dictionary mapping from device ID to ExtendedDevice
*/
async function fetchExtendedDeviceInformation(matrixClient) {
const {
devices
} = await matrixClient.getDevices();
const devicesDict = {};
for (const device of devices) {
devicesDict[device.device_id] = _objectSpread(_objectSpread(_objectSpread({}, device), {}, {
isVerified: await (0, _isDeviceVerified.isDeviceVerified)(matrixClient, device.device_id)
}, parseDeviceExtendedInformation(matrixClient, device)), (0, _parseUserAgent.parseUserAgent)(device[_matrix.UNSTABLE_MSC3852_LAST_SEEN_UA.name]));
}
return devicesDict;
}
let OwnDevicesError = exports.OwnDevicesError = /*#__PURE__*/function (OwnDevicesError) {
OwnDevicesError["Unsupported"] = "Unsupported";
OwnDevicesError["Default"] = "Default";
return OwnDevicesError;
}({});
const useOwnDevices = () => {
const sdkContext = (0, _react.useContext)(_SDKContext.SDKContext);
const matrixClient = sdkContext.client;
const currentDeviceId = matrixClient.getDeviceId();
const userId = matrixClient.getSafeUserId();
const [devices, setDevices] = (0, _react.useState)({});
const [dehydratedDeviceId, setDehydratedDeviceId] = (0, _react.useState)(undefined);
const [pushers, setPushers] = (0, _react.useState)([]);
const [localNotificationSettings, setLocalNotificationSettings] = (0, _react.useState)(new Map());
const [isLoadingDeviceList, setIsLoadingDeviceList] = (0, _react.useState)(true);
const [supportsMSC3881, setSupportsMSC3881] = (0, _react.useState)(true); // optimisticly saying yes!
const [error, setError] = (0, _react.useState)();
(0, _react.useEffect)(() => {
matrixClient.doesServerSupportUnstableFeature("org.matrix.msc3881").then(hasSupport => {
setSupportsMSC3881(hasSupport);
});
}, [matrixClient]);
const refreshDevices = (0, _react.useCallback)(async () => {
setIsLoadingDeviceList(true);
try {
const devices = await fetchExtendedDeviceInformation(matrixClient);
setDevices(devices);
const {
pushers
} = await matrixClient.getPushers();
setPushers(pushers);
const notificationSettings = new Map();
Object.keys(devices).forEach(deviceId => {
const eventType = `${_matrix.LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
const event = matrixClient.getAccountData(eventType);
if (event) {
notificationSettings.set(deviceId, event.getContent());
}
});
setLocalNotificationSettings(notificationSettings);
const ownUserId = matrixClient.getUserId();
const userDevices = (await matrixClient.getCrypto()?.getUserDeviceInfo([ownUserId]))?.get(ownUserId);
const dehydratedDeviceIds = [];
for (const device of userDevices?.values() ?? []) {
if (device.dehydrated) {
dehydratedDeviceIds.push(device.deviceId);
}
}
// If the user has exactly one device marked as dehydrated, we consider
// that as the dehydrated device, and hide it as a normal device (but
// indicate that the user is using a dehydrated device). If the user has
// more than one, that is anomalous, and we show all the devices so that
// nothing is hidden.
setDehydratedDeviceId(dehydratedDeviceIds.length == 1 ? dehydratedDeviceIds[0] : undefined);
setIsLoadingDeviceList(false);
} catch (error) {
if (error.httpStatus == 404) {
// 404 probably means the HS doesn't yet support the API.
setError(OwnDevicesError.Unsupported);
} else {
_logger.logger.error("Error loading sessions:", error);
setError(OwnDevicesError.Default);
}
setIsLoadingDeviceList(false);
}
}, [matrixClient]);
(0, _react.useEffect)(() => {
refreshDevices();
}, [refreshDevices]);
(0, _react.useEffect)(() => {
const deviceIds = Object.keys(devices);
// empty devices means devices have not been fetched yet
// as there is always at least the current device
if (deviceIds.length) {
(0, _clientInformation.pruneClientInformation)(deviceIds, matrixClient);
}
}, [devices, matrixClient]);
(0, _useEventEmitter.useEventEmitter)(matrixClient, _crypto.CryptoEvent.DevicesUpdated, users => {
if (users.includes(userId)) {
refreshDevices();
}
});
(0, _useEventEmitter.useEventEmitter)(matrixClient, _matrix.ClientEvent.AccountData, event => {
const type = event.getType();
if (type.startsWith(_matrix.LOCAL_NOTIFICATION_SETTINGS_PREFIX.name)) {
const newSettings = new Map(localNotificationSettings);
const deviceId = type.slice(type.lastIndexOf(".") + 1);
newSettings.set(deviceId, event.getContent());
setLocalNotificationSettings(newSettings);
}
});
const isCurrentDeviceVerified = !!devices[currentDeviceId]?.isVerified;
const requestDeviceVerification = isCurrentDeviceVerified && userId ? async deviceId => {
return await matrixClient.getCrypto().requestDeviceVerification(userId, deviceId);
} : undefined;
const saveDeviceName = (0, _react.useCallback)(async (deviceId, deviceName) => {
const device = devices[deviceId];
// no change
if (deviceName === device?.display_name) {
return;
}
try {
await matrixClient.setDeviceDetails(deviceId, {
display_name: deviceName
});
await refreshDevices();
} catch (error) {
_logger.logger.error("Error setting device name", error);
throw new Error((0, _languageHandler._t)("settings|sessions|error_set_name"));
}
}, [matrixClient, devices, refreshDevices]);
const setPushNotifications = (0, _react.useCallback)(async (deviceId, enabled) => {
try {
const pusher = pushers.find(pusher => pusher[_matrix.PUSHER_DEVICE_ID.name] === deviceId);
if (pusher) {
await matrixClient.setPusher(_objectSpread(_objectSpread({}, pusher), {}, {
[_matrix.PUSHER_ENABLED.name]: enabled
}));
} else if (localNotificationSettings.has(deviceId)) {
await matrixClient.setLocalNotificationSettings(deviceId, {
is_silenced: !enabled
});
}
} catch (error) {
_logger.logger.error("Error setting pusher state", error);
throw new Error((0, _languageHandler._t)("settings|sessions|error_pusher_state"));
} finally {
await refreshDevices();
}
}, [matrixClient, pushers, localNotificationSettings, refreshDevices]);
return {
devices,
dehydratedDeviceId,
pushers,
localNotificationSettings,
currentDeviceId,
isLoadingDeviceList,
error,
requestDeviceVerification,
refreshDevices,
saveDeviceName,
setPushNotifications,
supportsMSC3881
};
};
exports.useOwnDevices = useOwnDevices;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJyZXF1aXJlIiwiX21hdHJpeCIsIl9sb2dnZXIiLCJfY3J5cHRvIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9jbGllbnRJbmZvcm1hdGlvbiIsIl91c2VFdmVudEVtaXR0ZXIiLCJfcGFyc2VVc2VyQWdlbnQiLCJfaXNEZXZpY2VWZXJpZmllZCIsIl9TREtDb250ZXh0Iiwib3duS2V5cyIsImUiLCJyIiwidCIsIk9iamVjdCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwicGFyc2VEZXZpY2VFeHRlbmRlZEluZm9ybWF0aW9uIiwibWF0cml4Q2xpZW50IiwiZGV2aWNlIiwibmFtZSIsInZlcnNpb24iLCJ1cmwiLCJnZXREZXZpY2VDbGllbnRJbmZvcm1hdGlvbiIsImRldmljZV9pZCIsImFwcE5hbWUiLCJhcHBWZXJzaW9uIiwiZmV0Y2hFeHRlbmRlZERldmljZUluZm9ybWF0aW9uIiwiZGV2aWNlcyIsImdldERldmljZXMiLCJkZXZpY2VzRGljdCIsImlzVmVyaWZpZWQiLCJpc0RldmljZVZlcmlmaWVkIiwicGFyc2VVc2VyQWdlbnQiLCJVTlNUQUJMRV9NU0MzODUyX0xBU1RfU0VFTl9VQSIsIk93bkRldmljZXNFcnJvciIsImV4cG9ydHMiLCJ1c2VPd25EZXZpY2VzIiwic2RrQ29udGV4dCIsInVzZUNvbnRleHQiLCJTREtDb250ZXh0IiwiY2xpZW50IiwiY3VycmVudERldmljZUlkIiwiZ2V0RGV2aWNlSWQiLCJ1c2VySWQiLCJnZXRTYWZlVXNlcklkIiwic2V0RGV2aWNlcyIsInVzZVN0YXRlIiwiZGVoeWRyYXRlZERldmljZUlkIiwic2V0RGVoeWRyYXRlZERldmljZUlkIiwidW5kZWZpbmVkIiwicHVzaGVycyIsInNldFB1c2hlcnMiLCJsb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzIiwic2V0TG9jYWxOb3RpZmljYXRpb25TZXR0aW5ncyIsIk1hcCIsImlzTG9hZGluZ0RldmljZUxpc3QiLCJzZXRJc0xvYWRpbmdEZXZpY2VMaXN0Iiwic3VwcG9ydHNNU0MzODgxIiwic2V0U3VwcG9ydHNNU0MzODgxIiwiZXJyb3IiLCJzZXRFcnJvciIsInVzZUVmZmVjdCIsImRvZXNTZXJ2ZXJTdXBwb3J0VW5zdGFibGVGZWF0dXJlIiwidGhlbiIsImhhc1N1cHBvcnQiLCJyZWZyZXNoRGV2aWNlcyIsInVzZUNhbGxiYWNrIiwiZ2V0UHVzaGVycyIsIm5vdGlmaWNhdGlvblNldHRpbmdzIiwiZGV2aWNlSWQiLCJldmVudFR5cGUiLCJMT0NBTF9OT1RJRklDQVRJT05fU0VUVElOR1NfUFJFRklYIiwiZXZlbnQiLCJnZXRBY2NvdW50RGF0YSIsInNldCIsImdldENvbnRlbnQiLCJvd25Vc2VySWQiLCJnZXRVc2VySWQiLCJ1c2VyRGV2aWNlcyIsImdldENyeXB0byIsImdldFVzZXJEZXZpY2VJbmZvIiwiZ2V0IiwiZGVoeWRyYXRlZERldmljZUlkcyIsInZhbHVlcyIsImRlaHlkcmF0ZWQiLCJodHRwU3RhdHVzIiwiVW5zdXBwb3J0ZWQiLCJsb2dnZXIiLCJEZWZhdWx0IiwiZGV2aWNlSWRzIiwicHJ1bmVDbGllbnRJbmZvcm1hdGlvbiIsInVzZUV2ZW50RW1pdHRlciIsIkNyeXB0b0V2ZW50IiwiRGV2aWNlc1VwZGF0ZWQiLCJ1c2VycyIsImluY2x1ZGVzIiwiQ2xpZW50RXZlbnQiLCJBY2NvdW50RGF0YSIsInR5cGUiLCJnZXRUeXBlIiwic3RhcnRzV2l0aCIsIm5ld1NldHRpbmdzIiwic2xpY2UiLCJsYXN0SW5kZXhPZiIsImlzQ3VycmVudERldmljZVZlcmlmaWVkIiwicmVxdWVzdERldmljZVZlcmlmaWNhdGlvbiIsInNhdmVEZXZpY2VOYW1lIiwiZGV2aWNlTmFtZSIsImRpc3BsYXlfbmFtZSIsInNldERldmljZURldGFpbHMiLCJFcnJvciIsIl90Iiwic2V0UHVzaE5vdGlmaWNhdGlvbnMiLCJlbmFibGVkIiwicHVzaGVyIiwiZmluZCIsIlBVU0hFUl9ERVZJQ0VfSUQiLCJzZXRQdXNoZXIiLCJQVVNIRVJfRU5BQkxFRCIsImhhcyIsImlzX3NpbGVuY2VkIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlld3Mvc2V0dGluZ3MvZGV2aWNlcy91c2VPd25EZXZpY2VzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIyIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IHVzZUNhbGxiYWNrLCB1c2VDb250ZXh0LCB1c2VFZmZlY3QsIHVzZVN0YXRlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQge1xuICAgIENsaWVudEV2ZW50LFxuICAgIElNeURldmljZSxcbiAgICBJUHVzaGVyLFxuICAgIExPQ0FMX05PVElGSUNBVElPTl9TRVRUSU5HU19QUkVGSVgsXG4gICAgTWF0cml4Q2xpZW50LFxuICAgIE1hdHJpeEV2ZW50LFxuICAgIFBVU0hFUl9ERVZJQ0VfSUQsXG4gICAgUFVTSEVSX0VOQUJMRUQsXG4gICAgVU5TVEFCTEVfTVNDMzg1Ml9MQVNUX1NFRU5fVUEsXG4gICAgTWF0cml4RXJyb3IsXG4gICAgTG9jYWxOb3RpZmljYXRpb25TZXR0aW5ncyxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgVmVyaWZpY2F0aW9uUmVxdWVzdCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8tYXBpXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBDcnlwdG9FdmVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG9cIjtcblxuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi4vLi4vLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgeyBnZXREZXZpY2VDbGllbnRJbmZvcm1hdGlvbiwgcHJ1bmVDbGllbnRJbmZvcm1hdGlvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi91dGlscy9kZXZpY2UvY2xpZW50SW5mb3JtYXRpb25cIjtcbmltcG9ydCB7IERldmljZXNEaWN0aW9uYXJ5LCBFeHRlbmRlZERldmljZSwgRXh0ZW5kZWREZXZpY2VBcHBJbmZvIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IHVzZUV2ZW50RW1pdHRlciB9IGZyb20gXCIuLi8uLi8uLi8uLi9ob29rcy91c2VFdmVudEVtaXR0ZXJcIjtcbmltcG9ydCB7IHBhcnNlVXNlckFnZW50IH0gZnJvbSBcIi4uLy4uLy4uLy4uL3V0aWxzL2RldmljZS9wYXJzZVVzZXJBZ2VudFwiO1xuaW1wb3J0IHsgaXNEZXZpY2VWZXJpZmllZCB9IGZyb20gXCIuLi8uLi8uLi8uLi91dGlscy9kZXZpY2UvaXNEZXZpY2VWZXJpZmllZFwiO1xuaW1wb3J0IHsgU0RLQ29udGV4dCB9IGZyb20gXCIuLi8uLi8uLi8uLi9jb250ZXh0cy9TREtDb250ZXh0XCI7XG5cbmNvbnN0IHBhcnNlRGV2aWNlRXh0ZW5kZWRJbmZvcm1hdGlvbiA9IChtYXRyaXhDbGllbnQ6IE1hdHJpeENsaWVudCwgZGV2aWNlOiBJTXlEZXZpY2UpOiBFeHRlbmRlZERldmljZUFwcEluZm8gPT4ge1xuICAgIGNvbnN0IHsgbmFtZSwgdmVyc2lvbiwgdXJsIH0gPSBnZXREZXZpY2VDbGllbnRJbmZvcm1hdGlvbihtYXRyaXhDbGllbnQsIGRldmljZS5kZXZpY2VfaWQpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgYXBwTmFtZTogbmFtZSxcbiAgICAgICAgYXBwVmVyc2lvbjogdmVyc2lvbixcbiAgICAgICAgdXJsLFxuICAgIH07XG59O1xuXG4vKipcbiAqIEZldGNoIGV4dGVuZGVkIGRldGFpbHMgb2YgdGhlIHVzZXIncyBvd24gZGV2aWNlc1xuICpcbiAqIEBwYXJhbSBtYXRyaXhDbGllbnQgLSBNYXRyaXggQ2xpZW50XG4gKiBAcmV0dXJucyBBIGRpY3Rpb25hcnkgbWFwcGluZyBmcm9tIGRldmljZSBJRCB0byBFeHRlbmRlZERldmljZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hFeHRlbmRlZERldmljZUluZm9ybWF0aW9uKG1hdHJpeENsaWVudDogTWF0cml4Q2xpZW50KTogUHJvbWlzZTxEZXZpY2VzRGljdGlvbmFyeT4ge1xuICAgIGNvbnN0IHsgZGV2aWNlcyB9ID0gYXdhaXQgbWF0cml4Q2xpZW50LmdldERldmljZXMoKTtcblxuICAgIGNvbnN0IGRldmljZXNEaWN0OiBEZXZpY2VzRGljdGlvbmFyeSA9IHt9O1xuICAgIGZvciAoY29uc3QgZGV2aWNlIG9mIGRldmljZXMpIHtcbiAgICAgICAgZGV2aWNlc0RpY3RbZGV2aWNlLmRldmljZV9pZF0gPSB7XG4gICAgICAgICAgICAuLi5kZXZpY2UsXG4gICAgICAgICAgICBpc1ZlcmlmaWVkOiBhd2FpdCBpc0RldmljZVZlcmlmaWVkKG1hdHJpeENsaWVudCwgZGV2aWNlLmRldmljZV9pZCksXG4gICAgICAgICAgICAuLi5wYXJzZURldmljZUV4dGVuZGVkSW5mb3JtYXRpb24obWF0cml4Q2xpZW50LCBkZXZpY2UpLFxuICAgICAgICAgICAgLi4ucGFyc2VVc2VyQWdlbnQoZGV2aWNlW1VOU1RBQkxFX01TQzM4NTJfTEFTVF9TRUVOX1VBLm5hbWVdKSxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIGRldmljZXNEaWN0O1xufVxuXG5leHBvcnQgZW51bSBPd25EZXZpY2VzRXJyb3Ige1xuICAgIFVuc3VwcG9ydGVkID0gXCJVbnN1cHBvcnRlZFwiLFxuICAgIERlZmF1bHQgPSBcIkRlZmF1bHRcIixcbn1cbmV4cG9ydCB0eXBlIERldmljZXNTdGF0ZSA9IHtcbiAgICBkZXZpY2VzOiBEZXZpY2VzRGljdGlvbmFyeTtcbiAgICBkZWh5ZHJhdGVkRGV2aWNlSWQ/OiBzdHJpbmc7XG4gICAgcHVzaGVyczogSVB1c2hlcltdO1xuICAgIGxvY2FsTm90aWZpY2F0aW9uU2V0dGluZ3M6IE1hcDxzdHJpbmcsIExvY2FsTm90aWZpY2F0aW9uU2V0dGluZ3M+O1xuICAgIGN1cnJlbnREZXZpY2VJZDogc3RyaW5nO1xuICAgIGlzTG9hZGluZ0RldmljZUxpc3Q6IGJvb2xlYW47XG4gICAgLy8gbm90IHByb3ZpZGVkIHdoZW4gY3VycmVudCBzZXNzaW9uIGNhbm5vdCByZXF1ZXN0IHZlcmlmaWNhdGlvblxuICAgIHJlcXVlc3REZXZpY2VWZXJpZmljYXRpb24/OiAoZGV2aWNlSWQ6IEV4dGVuZGVkRGV2aWNlW1wiZGV2aWNlX2lkXCJdKSA9PiBQcm9taXNlPFZlcmlmaWNhdGlvblJlcXVlc3Q+O1xuICAgIHJlZnJlc2hEZXZpY2VzOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAgIHNhdmVEZXZpY2VOYW1lOiAoZGV2aWNlSWQ6IEV4dGVuZGVkRGV2aWNlW1wiZGV2aWNlX2lkXCJdLCBkZXZpY2VOYW1lOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD47XG4gICAgc2V0UHVzaE5vdGlmaWNhdGlvbnM6IChkZXZpY2VJZDogRXh0ZW5kZWREZXZpY2VbXCJkZXZpY2VfaWRcIl0sIGVuYWJsZWQ6IGJvb2xlYW4pID0+IFByb21pc2U8dm9pZD47XG4gICAgZXJyb3I/OiBPd25EZXZpY2VzRXJyb3I7XG4gICAgc3VwcG9ydHNNU0MzODgxPzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbn07XG5leHBvcnQgY29uc3QgdXNlT3duRGV2aWNlcyA9ICgpOiBEZXZpY2VzU3RhdGUgPT4ge1xuICAgIGNvbnN0IHNka0NvbnRleHQgPSB1c2VDb250ZXh0KFNES0NvbnRleHQpO1xuICAgIGNvbnN0IG1hdHJpeENsaWVudCA9IHNka0NvbnRleHQuY2xpZW50ITtcblxuICAgIGNvbnN0IGN1cnJlbnREZXZpY2VJZCA9IG1hdHJpeENsaWVudC5nZXREZXZpY2VJZCgpITtcbiAgICBjb25zdCB1c2VySWQgPSBtYXRyaXhDbGllbnQuZ2V0U2FmZVVzZXJJZCgpO1xuXG4gICAgY29uc3QgW2RldmljZXMsIHNldERldmljZXNdID0gdXNlU3RhdGU8RGV2aWNlc1N0YXRlW1wiZGV2aWNlc1wiXT4oe30pO1xuICAgIGNvbnN0IFtkZWh5ZHJhdGVkRGV2aWNlSWQsIHNldERlaHlkcmF0ZWREZXZpY2VJZF0gPSB1c2VTdGF0ZTxEZXZpY2VzU3RhdGVbXCJkZWh5ZHJhdGVkRGV2aWNlSWRcIl0+KHVuZGVmaW5lZCk7XG4gICAgY29uc3QgW3B1c2hlcnMsIHNldFB1c2hlcnNdID0gdXNlU3RhdGU8RGV2aWNlc1N0YXRlW1wicHVzaGVyc1wiXT4oW10pO1xuICAgIGNvbnN0IFtsb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzLCBzZXRMb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzXSA9IHVzZVN0YXRlPFxuICAgICAgICBEZXZpY2VzU3RhdGVbXCJsb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzXCJdXG4gICAgPihuZXcgTWFwPHN0cmluZywgTG9jYWxOb3RpZmljYXRpb25TZXR0aW5ncz4oKSk7XG4gICAgY29uc3QgW2lzTG9hZGluZ0RldmljZUxpc3QsIHNldElzTG9hZGluZ0RldmljZUxpc3RdID0gdXNlU3RhdGUodHJ1ZSk7XG4gICAgY29uc3QgW3N1cHBvcnRzTVNDMzg4MSwgc2V0U3VwcG9ydHNNU0MzODgxXSA9IHVzZVN0YXRlKHRydWUpOyAvLyBvcHRpbWlzdGljbHkgc2F5aW5nIHllcyFcblxuICAgIGNvbnN0IFtlcnJvciwgc2V0RXJyb3JdID0gdXNlU3RhdGU8T3duRGV2aWNlc0Vycm9yPigpO1xuXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgbWF0cml4Q2xpZW50LmRvZXNTZXJ2ZXJTdXBwb3J0VW5zdGFibGVGZWF0dXJlKFwib3JnLm1hdHJpeC5tc2MzODgxXCIpLnRoZW4oKGhhc1N1cHBvcnQpID0+IHtcbiAgICAgICAgICAgIHNldFN1cHBvcnRzTVNDMzg4MShoYXNTdXBwb3J0KTtcbiAgICAgICAgfSk7XG4gICAgfSwgW21hdHJpeENsaWVudF0pO1xuXG4gICAgY29uc3QgcmVmcmVzaERldmljZXMgPSB1c2VDYWxsYmFjayhhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIHNldElzTG9hZGluZ0RldmljZUxpc3QodHJ1ZSk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBkZXZpY2VzID0gYXdhaXQgZmV0Y2hFeHRlbmRlZERldmljZUluZm9ybWF0aW9uKG1hdHJpeENsaWVudCk7XG4gICAgICAgICAgICBzZXREZXZpY2VzKGRldmljZXMpO1xuXG4gICAgICAgICAgICBjb25zdCB7IHB1c2hlcnMgfSA9IGF3YWl0IG1hdHJpeENsaWVudC5nZXRQdXNoZXJzKCk7XG4gICAgICAgICAgICBzZXRQdXNoZXJzKHB1c2hlcnMpO1xuXG4gICAgICAgICAgICBjb25zdCBub3RpZmljYXRpb25TZXR0aW5ncyA9IG5ldyBNYXA8c3RyaW5nLCBMb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzPigpO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoZGV2aWNlcykuZm9yRWFjaCgoZGV2aWNlSWQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBldmVudFR5cGUgPSBgJHtMT0NBTF9OT1RJRklDQVRJT05fU0VUVElOR1NfUFJFRklYLm5hbWV9LiR7ZGV2aWNlSWR9YDtcbiAgICAgICAgICAgICAgICBjb25zdCBldmVudCA9IG1hdHJpeENsaWVudC5nZXRBY2NvdW50RGF0YShldmVudFR5cGUpO1xuICAgICAgICAgICAgICAgIGlmIChldmVudCkge1xuICAgICAgICAgICAgICAgICAgICBub3RpZmljYXRpb25TZXR0aW5ncy5zZXQoZGV2aWNlSWQsIGV2ZW50LmdldENvbnRlbnQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBzZXRMb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzKG5vdGlmaWNhdGlvblNldHRpbmdzKTtcblxuICAgICAgICAgICAgY29uc3Qgb3duVXNlcklkID0gbWF0cml4Q2xpZW50LmdldFVzZXJJZCgpITtcbiAgICAgICAgICAgIGNvbnN0IHVzZXJEZXZpY2VzID0gKGF3YWl0IG1hdHJpeENsaWVudC5nZXRDcnlwdG8oKT8uZ2V0VXNlckRldmljZUluZm8oW293blVzZXJJZF0pKT8uZ2V0KG93blVzZXJJZCk7XG4gICAgICAgICAgICBjb25zdCBkZWh5ZHJhdGVkRGV2aWNlSWRzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICAgICAgZm9yIChjb25zdCBkZXZpY2Ugb2YgdXNlckRldmljZXM/LnZhbHVlcygpID8/IFtdKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRldmljZS5kZWh5ZHJhdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGRlaHlkcmF0ZWREZXZpY2VJZHMucHVzaChkZXZpY2UuZGV2aWNlSWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIElmIHRoZSB1c2VyIGhhcyBleGFjdGx5IG9uZSBkZXZpY2UgbWFya2VkIGFzIGRlaHlkcmF0ZWQsIHdlIGNvbnNpZGVyXG4gICAgICAgICAgICAvLyB0aGF0IGFzIHRoZSBkZWh5ZHJhdGVkIGRldmljZSwgYW5kIGhpZGUgaXQgYXMgYSBub3JtYWwgZGV2aWNlIChidXRcbiAgICAgICAgICAgIC8vIGluZGljYXRlIHRoYXQgdGhlIHVzZXIgaXMgdXNpbmcgYSBkZWh5ZHJhdGVkIGRldmljZSkuICBJZiB0aGUgdXNlciBoYXNcbiAgICAgICAgICAgIC8vIG1vcmUgdGhhbiBvbmUsIHRoYXQgaXMgYW5vbWFsb3VzLCBhbmQgd2Ugc2hvdyBhbGwgdGhlIGRldmljZXMgc28gdGhhdFxuICAgICAgICAgICAgLy8gbm90aGluZyBpcyBoaWRkZW4uXG4gICAgICAgICAgICBzZXREZWh5ZHJhdGVkRGV2aWNlSWQoZGVoeWRyYXRlZERldmljZUlkcy5sZW5ndGggPT0gMSA/IGRlaHlkcmF0ZWREZXZpY2VJZHNbMF0gOiB1bmRlZmluZWQpO1xuXG4gICAgICAgICAgICBzZXRJc0xvYWRpbmdEZXZpY2VMaXN0KGZhbHNlKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGlmICgoZXJyb3IgYXMgTWF0cml4RXJyb3IpLmh0dHBTdGF0dXMgPT0gNDA0KSB7XG4gICAgICAgICAgICAgICAgLy8gNDA0IHByb2JhYmx5IG1lYW5zIHRoZSBIUyBkb2Vzbid0IHlldCBzdXBwb3J0IHRoZSBBUEkuXG4gICAgICAgICAgICAgICAgc2V0RXJyb3IoT3duRGV2aWNlc0Vycm9yLlVuc3VwcG9ydGVkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiRXJyb3IgbG9hZGluZyBzZXNzaW9uczpcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIHNldEVycm9yKE93bkRldmljZXNFcnJvci5EZWZhdWx0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNldElzTG9hZGluZ0RldmljZUxpc3QoZmFsc2UpO1xuICAgICAgICB9XG4gICAgfSwgW21hdHJpeENsaWVudF0pO1xuXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgcmVmcmVzaERldmljZXMoKTtcbiAgICB9LCBbcmVmcmVzaERldmljZXNdKTtcblxuICAgIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIGNvbnN0IGRldmljZUlkcyA9IE9iamVjdC5rZXlzKGRldmljZXMpO1xuICAgICAgICAvLyBlbXB0eSBkZXZpY2VzIG1lYW5zIGRldmljZXMgaGF2ZSBub3QgYmVlbiBmZXRjaGVkIHlldFxuICAgICAgICAvLyBhcyB0aGVyZSBpcyBhbHdheXMgYXQgbGVhc3QgdGhlIGN1cnJlbnQgZGV2aWNlXG4gICAgICAgIGlmIChkZXZpY2VJZHMubGVuZ3RoKSB7XG4gICAgICAgICAgICBwcnVuZUNsaWVudEluZm9ybWF0aW9uKGRldmljZUlkcywgbWF0cml4Q2xpZW50KTtcbiAgICAgICAgfVxuICAgIH0sIFtkZXZpY2VzLCBtYXRyaXhDbGllbnRdKTtcblxuICAgIHVzZUV2ZW50RW1pdHRlcihtYXRyaXhDbGllbnQsIENyeXB0b0V2ZW50LkRldmljZXNVcGRhdGVkLCAodXNlcnM6IHN0cmluZ1tdKTogdm9pZCA9PiB7XG4gICAgICAgIGlmICh1c2Vycy5pbmNsdWRlcyh1c2VySWQpKSB7XG4gICAgICAgICAgICByZWZyZXNoRGV2aWNlcygpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICB1c2VFdmVudEVtaXR0ZXIobWF0cml4Q2xpZW50LCBDbGllbnRFdmVudC5BY2NvdW50RGF0YSwgKGV2ZW50OiBNYXRyaXhFdmVudCk6IHZvaWQgPT4ge1xuICAgICAgICBjb25zdCB0eXBlID0gZXZlbnQuZ2V0VHlwZSgpO1xuICAgICAgICBpZiAodHlwZS5zdGFydHNXaXRoKExPQ0FMX05PVElGSUNBVElPTl9TRVRUSU5HU19QUkVGSVgubmFtZSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG5ld1NldHRpbmdzID0gbmV3IE1hcChsb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzKTtcbiAgICAgICAgICAgIGNvbnN0IGRldmljZUlkID0gdHlwZS5zbGljZSh0eXBlLmxhc3RJbmRleE9mKFwiLlwiKSArIDEpO1xuICAgICAgICAgICAgbmV3U2V0dGluZ3Muc2V0KGRldmljZUlkLCBldmVudC5nZXRDb250ZW50PExvY2FsTm90aWZpY2F0aW9uU2V0dGluZ3M+KCkpO1xuICAgICAgICAgICAgc2V0TG9jYWxOb3RpZmljYXRpb25TZXR0aW5ncyhuZXdTZXR0aW5ncyk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGNvbnN0IGlzQ3VycmVudERldmljZVZlcmlmaWVkID0gISFkZXZpY2VzW2N1cnJlbnREZXZpY2VJZF0/LmlzVmVyaWZpZWQ7XG5cbiAgICBjb25zdCByZXF1ZXN0RGV2aWNlVmVyaWZpY2F0aW9uID1cbiAgICAgICAgaXNDdXJyZW50RGV2aWNlVmVyaWZpZWQgJiYgdXNlcklkXG4gICAgICAgICAgICA/IGFzeW5jIChkZXZpY2VJZDogRXh0ZW5kZWREZXZpY2VbXCJkZXZpY2VfaWRcIl0pOiBQcm9taXNlPFZlcmlmaWNhdGlvblJlcXVlc3Q+ID0+IHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBtYXRyaXhDbGllbnQuZ2V0Q3J5cHRvKCkhLnJlcXVlc3REZXZpY2VWZXJpZmljYXRpb24odXNlcklkLCBkZXZpY2VJZCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgc2F2ZURldmljZU5hbWUgPSB1c2VDYWxsYmFjayhcbiAgICAgICAgYXN5bmMgKGRldmljZUlkOiBFeHRlbmRlZERldmljZVtcImRldmljZV9pZFwiXSwgZGV2aWNlTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICBjb25zdCBkZXZpY2UgPSBkZXZpY2VzW2RldmljZUlkXTtcblxuICAgICAgICAgICAgLy8gbm8gY2hhbmdlXG4gICAgICAgICAgICBpZiAoZGV2aWNlTmFtZSA9PT0gZGV2aWNlPy5kaXNwbGF5X25hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgbWF0cml4Q2xpZW50LnNldERldmljZURldGFpbHMoZGV2aWNlSWQsIHsgZGlzcGxheV9uYW1lOiBkZXZpY2VOYW1lIH0pO1xuICAgICAgICAgICAgICAgIGF3YWl0IHJlZnJlc2hEZXZpY2VzKCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkVycm9yIHNldHRpbmcgZGV2aWNlIG5hbWVcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihfdChcInNldHRpbmdzfHNlc3Npb25zfGVycm9yX3NldF9uYW1lXCIpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgW21hdHJpeENsaWVudCwgZGV2aWNlcywgcmVmcmVzaERldmljZXNdLFxuICAgICk7XG5cbiAgICBjb25zdCBzZXRQdXNoTm90aWZpY2F0aW9ucyA9IHVzZUNhbGxiYWNrKFxuICAgICAgICBhc3luYyAoZGV2aWNlSWQ6IEV4dGVuZGVkRGV2aWNlW1wiZGV2aWNlX2lkXCJdLCBlbmFibGVkOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHB1c2hlciA9IHB1c2hlcnMuZmluZCgocHVzaGVyKSA9PiBwdXNoZXJbUFVTSEVSX0RFVklDRV9JRC5uYW1lXSA9PT0gZGV2aWNlSWQpO1xuICAgICAgICAgICAgICAgIGlmIChwdXNoZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgbWF0cml4Q2xpZW50LnNldFB1c2hlcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi5wdXNoZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBbUFVTSEVSX0VOQUJMRUQubmFtZV06IGVuYWJsZWQsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobG9jYWxOb3RpZmljYXRpb25TZXR0aW5ncy5oYXMoZGV2aWNlSWQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IG1hdHJpeENsaWVudC5zZXRMb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzKGRldmljZUlkLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpc19zaWxlbmNlZDogIWVuYWJsZWQsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiRXJyb3Igc2V0dGluZyBwdXNoZXIgc3RhdGVcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihfdChcInNldHRpbmdzfHNlc3Npb25zfGVycm9yX3B1c2hlcl9zdGF0ZVwiKSk7XG4gICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHJlZnJlc2hEZXZpY2VzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFttYXRyaXhDbGllbnQsIHB1c2hlcnMsIGxvY2FsTm90aWZpY2F0aW9uU2V0dGluZ3MsIHJlZnJlc2hEZXZpY2VzXSxcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgZGV2aWNlcyxcbiAgICAgICAgZGVoeWRyYXRlZERldmljZUlkLFxuICAgICAgICBwdXNoZXJzLFxuICAgICAgICBsb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzLFxuICAgICAgICBjdXJyZW50RGV2aWNlSWQsXG4gICAgICAgIGlzTG9hZGluZ0RldmljZUxpc3QsXG4gICAgICAgIGVycm9yLFxuICAgICAgICByZXF1ZXN0RGV2aWNlVmVyaWZpY2F0aW9uLFxuICAgICAgICByZWZyZXNoRGV2aWNlcyxcbiAgICAgICAgc2F2ZURldmljZU5hbWUsXG4gICAgICAgIHNldFB1c2hOb3RpZmljYXRpb25zLFxuICAgICAgICBzdXBwb3J0c01TQzM4ODEsXG4gICAgfTtcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFRQSxJQUFBQSxNQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFjQSxJQUFBRSxPQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxPQUFBLEdBQUFILE9BQUE7QUFFQSxJQUFBSSxnQkFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssa0JBQUEsR0FBQUwsT0FBQTtBQUVBLElBQUFNLGdCQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxlQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSxpQkFBQSxHQUFBUixPQUFBO0FBQ0EsSUFBQVMsV0FBQSxHQUFBVCxPQUFBO0FBQTZELFNBQUFVLFFBQUFDLENBQUEsRUFBQUMsQ0FBQSxRQUFBQyxDQUFBLEdBQUFDLE1BQUEsQ0FBQUMsSUFBQSxDQUFBSixDQUFBLE9BQUFHLE1BQUEsQ0FBQUUscUJBQUEsUUFBQUMsQ0FBQSxHQUFBSCxNQUFBLENBQUFFLHFCQUFBLENBQUFMLENBQUEsR0FBQUMsQ0FBQSxLQUFBSyxDQUFBLEdBQUFBLENBQUEsQ0FBQUMsTUFBQSxXQUFBTixDQUFBLFdBQUFFLE1BQUEsQ0FBQUssd0JBQUEsQ0FBQVIsQ0FBQSxFQUFBQyxDQUFBLEVBQUFRLFVBQUEsT0FBQVAsQ0FBQSxDQUFBUSxJQUFBLENBQUFDLEtBQUEsQ0FBQVQsQ0FBQSxFQUFBSSxDQUFBLFlBQUFKLENBQUE7QUFBQSxTQUFBVSxjQUFBWixDQUFBLGFBQUFDLENBQUEsTUFBQUEsQ0FBQSxHQUFBWSxTQUFBLENBQUFDLE1BQUEsRUFBQWIsQ0FBQSxVQUFBQyxDQUFBLFdBQUFXLFNBQUEsQ0FBQVosQ0FBQSxJQUFBWSxTQUFBLENBQUFaLENBQUEsUUFBQUEsQ0FBQSxPQUFBRixPQUFBLENBQUFJLE1BQUEsQ0FBQUQsQ0FBQSxPQUFBYSxPQUFBLFdBQUFkLENBQUEsUUFBQWUsZ0JBQUEsQ0FBQUMsT0FBQSxFQUFBakIsQ0FBQSxFQUFBQyxDQUFBLEVBQUFDLENBQUEsQ0FBQUQsQ0FBQSxTQUFBRSxNQUFBLENBQUFlLHlCQUFBLEdBQUFmLE1BQUEsQ0FBQWdCLGdCQUFBLENBQUFuQixDQUFBLEVBQUFHLE1BQUEsQ0FBQWUseUJBQUEsQ0FBQWhCLENBQUEsS0FBQUgsT0FBQSxDQUFBSSxNQUFBLENBQUFELENBQUEsR0FBQWEsT0FBQSxXQUFBZCxDQUFBLElBQUFFLE1BQUEsQ0FBQWlCLGNBQUEsQ0FBQXBCLENBQUEsRUFBQUMsQ0FBQSxFQUFBRSxNQUFBLENBQUFLLHdCQUFBLENBQUFOLENBQUEsRUFBQUQsQ0FBQSxpQkFBQUQsQ0FBQSxJQWhDN0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUE0QkEsTUFBTXFCLDhCQUE4QixHQUFHQSxDQUFDQyxZQUEwQixFQUFFQyxNQUFpQixLQUE0QjtFQUM3RyxNQUFNO0lBQUVDLElBQUk7SUFBRUMsT0FBTztJQUFFQztFQUFJLENBQUMsR0FBRyxJQUFBQyw2Q0FBMEIsRUFBQ0wsWUFBWSxFQUFFQyxNQUFNLENBQUNLLFNBQVMsQ0FBQztFQUV6RixPQUFPO0lBQ0hDLE9BQU8sRUFBRUwsSUFBSTtJQUNiTSxVQUFVLEVBQUVMLE9BQU87SUFDbkJDO0VBQ0osQ0FBQztBQUNMLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sZUFBZUssOEJBQThCQSxDQUFDVCxZQUEwQixFQUE4QjtFQUN6RyxNQUFNO0lBQUVVO0VBQVEsQ0FBQyxHQUFHLE1BQU1WLFlBQVksQ0FBQ1csVUFBVSxDQUFDLENBQUM7RUFFbkQsTUFBTUMsV0FBOEIsR0FBRyxDQUFDLENBQUM7RUFDekMsS0FBSyxNQUFNWCxNQUFNLElBQUlTLE9BQU8sRUFBRTtJQUMxQkUsV0FBVyxDQUFDWCxNQUFNLENBQUNLLFNBQVMsQ0FBQyxHQUFBaEIsYUFBQSxDQUFBQSxhQUFBLENBQUFBLGFBQUEsS0FDdEJXLE1BQU07TUFDVFksVUFBVSxFQUFFLE1BQU0sSUFBQUMsa0NBQWdCLEVBQUNkLFlBQVksRUFBRUMsTUFBTSxDQUFDSyxTQUFTO0lBQUMsR0FDL0RQLDhCQUE4QixDQUFDQyxZQUFZLEVBQUVDLE1BQU0sQ0FBQyxHQUNwRCxJQUFBYyw4QkFBYyxFQUFDZCxNQUFNLENBQUNlLHFDQUE2QixDQUFDZCxJQUFJLENBQUMsQ0FBQyxDQUNoRTtFQUNMO0VBQ0EsT0FBT1UsV0FBVztBQUN0QjtBQUFDLElBRVdLLGVBQWUsR0FBQUMsT0FBQSxDQUFBRCxlQUFBLDBCQUFmQSxlQUFlO0VBQWZBLGVBQWU7RUFBZkEsZUFBZTtFQUFBLE9BQWZBLGVBQWU7QUFBQTtBQW1CcEIsTUFBTUUsYUFBYSxHQUFHQSxDQUFBLEtBQW9CO0VBQzdDLE1BQU1DLFVBQVUsR0FBRyxJQUFBQyxpQkFBVSxFQUFDQyxzQkFBVSxDQUFDO0VBQ3pDLE1BQU10QixZQUFZLEdBQUdvQixVQUFVLENBQUNHLE1BQU87RUFFdkMsTUFBTUMsZUFBZSxHQUFHeEIsWUFBWSxDQUFDeUIsV0FBVyxDQUFDLENBQUU7RUFDbkQsTUFBTUMsTUFBTSxHQUFHMUIsWUFBWSxDQUFDMkIsYUFBYSxDQUFDLENBQUM7RUFFM0MsTUFBTSxDQUFDakIsT0FBTyxFQUFFa0IsVUFBVSxDQUFDLEdBQUcsSUFBQUMsZUFBUSxFQUEwQixDQUFDLENBQUMsQ0FBQztFQUNuRSxNQUFNLENBQUNDLGtCQUFrQixFQUFFQyxxQkFBcUIsQ0FBQyxHQUFHLElBQUFGLGVBQVEsRUFBcUNHLFNBQVMsQ0FBQztFQUMzRyxNQUFNLENBQUNDLE9BQU8sRUFBRUMsVUFBVSxDQUFDLEdBQUcsSUFBQUwsZUFBUSxFQUEwQixFQUFFLENBQUM7RUFDbkUsTUFBTSxDQUFDTSx5QkFBeUIsRUFBRUMsNEJBQTRCLENBQUMsR0FBRyxJQUFBUCxlQUFRLEVBRXhFLElBQUlRLEdBQUcsQ0FBb0MsQ0FBQyxDQUFDO0VBQy9DLE1BQU0sQ0FBQ0MsbUJBQW1CLEVBQUVDLHNCQUFzQixDQUFDLEdBQUcsSUFBQVYsZUFBUSxFQUFDLElBQUksQ0FBQztFQUNwRSxNQUFNLENBQUNXLGVBQWUsRUFBRUMsa0JBQWtCLENBQUMsR0FBRyxJQUFBWixlQUFRLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzs7RUFFOUQsTUFBTSxDQUFDYSxLQUFLLEVBQUVDLFFBQVEsQ0FBQyxHQUFHLElBQUFkLGVBQVEsRUFBa0IsQ0FBQztFQUVyRCxJQUFBZSxnQkFBUyxFQUFDLE1BQU07SUFDWjVDLFlBQVksQ0FBQzZDLGdDQUFnQyxDQUFDLG9CQUFvQixDQUFDLENBQUNDLElBQUksQ0FBRUMsVUFBVSxJQUFLO01BQ3JGTixrQkFBa0IsQ0FBQ00sVUFBVSxDQUFDO0lBQ2xDLENBQUMsQ0FBQztFQUNOLENBQUMsRUFBRSxDQUFDL0MsWUFBWSxDQUFDLENBQUM7RUFFbEIsTUFBTWdELGNBQWMsR0FBRyxJQUFBQyxrQkFBVyxFQUFDLFlBQTJCO0lBQzFEVixzQkFBc0IsQ0FBQyxJQUFJLENBQUM7SUFDNUIsSUFBSTtNQUNBLE1BQU03QixPQUFPLEdBQUcsTUFBTUQsOEJBQThCLENBQUNULFlBQVksQ0FBQztNQUNsRTRCLFVBQVUsQ0FBQ2xCLE9BQU8sQ0FBQztNQUVuQixNQUFNO1FBQUV1QjtNQUFRLENBQUMsR0FBRyxNQUFNakMsWUFBWSxDQUFDa0QsVUFBVSxDQUFDLENBQUM7TUFDbkRoQixVQUFVLENBQUNELE9BQU8sQ0FBQztNQUVuQixNQUFNa0Isb0JBQW9CLEdBQUcsSUFBSWQsR0FBRyxDQUFvQyxDQUFDO01BQ3pFeEQsTUFBTSxDQUFDQyxJQUFJLENBQUM0QixPQUFPLENBQUMsQ0FBQ2pCLE9BQU8sQ0FBRTJELFFBQVEsSUFBSztRQUN2QyxNQUFNQyxTQUFTLEdBQUcsR0FBR0MsMENBQWtDLENBQUNwRCxJQUFJLElBQUlrRCxRQUFRLEVBQUU7UUFDMUUsTUFBTUcsS0FBSyxHQUFHdkQsWUFBWSxDQUFDd0QsY0FBYyxDQUFDSCxTQUFTLENBQUM7UUFDcEQsSUFBSUUsS0FBSyxFQUFFO1VBQ1BKLG9CQUFvQixDQUFDTSxHQUFHLENBQUNMLFFBQVEsRUFBRUcsS0FBSyxDQUFDRyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBQzFEO01BQ0osQ0FBQyxDQUFDO01BQ0Z0Qiw0QkFBNEIsQ0FBQ2Usb0JBQW9CLENBQUM7TUFFbEQsTUFBTVEsU0FBUyxHQUFHM0QsWUFBWSxDQUFDNEQsU0FBUyxDQUFDLENBQUU7TUFDM0MsTUFBTUMsV0FBVyxHQUFHLENBQUMsTUFBTTdELFlBQVksQ0FBQzhELFNBQVMsQ0FBQyxDQUFDLEVBQUVDLGlCQUFpQixDQUFDLENBQUNKLFNBQVMsQ0FBQyxDQUFDLEdBQUdLLEdBQUcsQ0FBQ0wsU0FBUyxDQUFDO01BQ3BHLE1BQU1NLG1CQUE2QixHQUFHLEVBQUU7TUFDeEMsS0FBSyxNQUFNaEUsTUFBTSxJQUFJNEQsV0FBVyxFQUFFSyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtRQUM5QyxJQUFJakUsTUFBTSxDQUFDa0UsVUFBVSxFQUFFO1VBQ25CRixtQkFBbUIsQ0FBQzdFLElBQUksQ0FBQ2EsTUFBTSxDQUFDbUQsUUFBUSxDQUFDO1FBQzdDO01BQ0o7TUFDQTtNQUNBO01BQ0E7TUFDQTtNQUNBO01BQ0FyQixxQkFBcUIsQ0FBQ2tDLG1CQUFtQixDQUFDekUsTUFBTSxJQUFJLENBQUMsR0FBR3lFLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxHQUFHakMsU0FBUyxDQUFDO01BRTNGTyxzQkFBc0IsQ0FBQyxLQUFLLENBQUM7SUFDakMsQ0FBQyxDQUFDLE9BQU9HLEtBQUssRUFBRTtNQUNaLElBQUtBLEtBQUssQ0FBaUIwQixVQUFVLElBQUksR0FBRyxFQUFFO1FBQzFDO1FBQ0F6QixRQUFRLENBQUMxQixlQUFlLENBQUNvRCxXQUFXLENBQUM7TUFDekMsQ0FBQyxNQUFNO1FBQ0hDLGNBQU0sQ0FBQzVCLEtBQUssQ0FBQyx5QkFBeUIsRUFBRUEsS0FBSyxDQUFDO1FBQzlDQyxRQUFRLENBQUMxQixlQUFlLENBQUNzRCxPQUFPLENBQUM7TUFDckM7TUFDQWhDLHNCQUFzQixDQUFDLEtBQUssQ0FBQztJQUNqQztFQUNKLENBQUMsRUFBRSxDQUFDdkMsWUFBWSxDQUFDLENBQUM7RUFFbEIsSUFBQTRDLGdCQUFTLEVBQUMsTUFBTTtJQUNaSSxjQUFjLENBQUMsQ0FBQztFQUNwQixDQUFDLEVBQUUsQ0FBQ0EsY0FBYyxDQUFDLENBQUM7RUFFcEIsSUFBQUosZ0JBQVMsRUFBQyxNQUFNO0lBQ1osTUFBTTRCLFNBQVMsR0FBRzNGLE1BQU0sQ0FBQ0MsSUFBSSxDQUFDNEIsT0FBTyxDQUFDO0lBQ3RDO0lBQ0E7SUFDQSxJQUFJOEQsU0FBUyxDQUFDaEYsTUFBTSxFQUFFO01BQ2xCLElBQUFpRix5Q0FBc0IsRUFBQ0QsU0FBUyxFQUFFeEUsWUFBWSxDQUFDO0lBQ25EO0VBQ0osQ0FBQyxFQUFFLENBQUNVLE9BQU8sRUFBRVYsWUFBWSxDQUFDLENBQUM7RUFFM0IsSUFBQTBFLGdDQUFlLEVBQUMxRSxZQUFZLEVBQUUyRSxtQkFBVyxDQUFDQyxjQUFjLEVBQUdDLEtBQWUsSUFBVztJQUNqRixJQUFJQSxLQUFLLENBQUNDLFFBQVEsQ0FBQ3BELE1BQU0sQ0FBQyxFQUFFO01BQ3hCc0IsY0FBYyxDQUFDLENBQUM7SUFDcEI7RUFDSixDQUFDLENBQUM7RUFFRixJQUFBMEIsZ0NBQWUsRUFBQzFFLFlBQVksRUFBRStFLG1CQUFXLENBQUNDLFdBQVcsRUFBR3pCLEtBQWtCLElBQVc7SUFDakYsTUFBTTBCLElBQUksR0FBRzFCLEtBQUssQ0FBQzJCLE9BQU8sQ0FBQyxDQUFDO0lBQzVCLElBQUlELElBQUksQ0FBQ0UsVUFBVSxDQUFDN0IsMENBQWtDLENBQUNwRCxJQUFJLENBQUMsRUFBRTtNQUMxRCxNQUFNa0YsV0FBVyxHQUFHLElBQUkvQyxHQUFHLENBQUNGLHlCQUF5QixDQUFDO01BQ3RELE1BQU1pQixRQUFRLEdBQUc2QixJQUFJLENBQUNJLEtBQUssQ0FBQ0osSUFBSSxDQUFDSyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO01BQ3RERixXQUFXLENBQUMzQixHQUFHLENBQUNMLFFBQVEsRUFBRUcsS0FBSyxDQUFDRyxVQUFVLENBQTRCLENBQUMsQ0FBQztNQUN4RXRCLDRCQUE0QixDQUFDZ0QsV0FBVyxDQUFDO0lBQzdDO0VBQ0osQ0FBQyxDQUFDO0VBRUYsTUFBTUcsdUJBQXVCLEdBQUcsQ0FBQyxDQUFDN0UsT0FBTyxDQUFDYyxlQUFlLENBQUMsRUFBRVgsVUFBVTtFQUV0RSxNQUFNMkUseUJBQXlCLEdBQzNCRCx1QkFBdUIsSUFBSTdELE1BQU0sR0FDM0IsTUFBTzBCLFFBQXFDLElBQW1DO0lBQzNFLE9BQU8sTUFBTXBELFlBQVksQ0FBQzhELFNBQVMsQ0FBQyxDQUFDLENBQUUwQix5QkFBeUIsQ0FBQzlELE1BQU0sRUFBRTBCLFFBQVEsQ0FBQztFQUN0RixDQUFDLEdBQ0RwQixTQUFTO0VBRW5CLE1BQU15RCxjQUFjLEdBQUcsSUFBQXhDLGtCQUFXLEVBQzlCLE9BQU9HLFFBQXFDLEVBQUVzQyxVQUFrQixLQUFvQjtJQUNoRixNQUFNekYsTUFBTSxHQUFHUyxPQUFPLENBQUMwQyxRQUFRLENBQUM7O0lBRWhDO0lBQ0EsSUFBSXNDLFVBQVUsS0FBS3pGLE1BQU0sRUFBRTBGLFlBQVksRUFBRTtNQUNyQztJQUNKO0lBRUEsSUFBSTtNQUNBLE1BQU0zRixZQUFZLENBQUM0RixnQkFBZ0IsQ0FBQ3hDLFFBQVEsRUFBRTtRQUFFdUMsWUFBWSxFQUFFRDtNQUFXLENBQUMsQ0FBQztNQUMzRSxNQUFNMUMsY0FBYyxDQUFDLENBQUM7SUFDMUIsQ0FBQyxDQUFDLE9BQU9OLEtBQUssRUFBRTtNQUNaNEIsY0FBTSxDQUFDNUIsS0FBSyxDQUFDLDJCQUEyQixFQUFFQSxLQUFLLENBQUM7TUFDaEQsTUFBTSxJQUFJbUQsS0FBSyxDQUFDLElBQUFDLG1CQUFFLEVBQUMsa0NBQWtDLENBQUMsQ0FBQztJQUMzRDtFQUNKLENBQUMsRUFDRCxDQUFDOUYsWUFBWSxFQUFFVSxPQUFPLEVBQUVzQyxjQUFjLENBQzFDLENBQUM7RUFFRCxNQUFNK0Msb0JBQW9CLEdBQUcsSUFBQTlDLGtCQUFXLEVBQ3BDLE9BQU9HLFFBQXFDLEVBQUU0QyxPQUFnQixLQUFvQjtJQUM5RSxJQUFJO01BQ0EsTUFBTUMsTUFBTSxHQUFHaEUsT0FBTyxDQUFDaUUsSUFBSSxDQUFFRCxNQUFNLElBQUtBLE1BQU0sQ0FBQ0Usd0JBQWdCLENBQUNqRyxJQUFJLENBQUMsS0FBS2tELFFBQVEsQ0FBQztNQUNuRixJQUFJNkMsTUFBTSxFQUFFO1FBQ1IsTUFBTWpHLFlBQVksQ0FBQ29HLFNBQVMsQ0FBQTlHLGFBQUEsQ0FBQUEsYUFBQSxLQUNyQjJHLE1BQU07VUFDVCxDQUFDSSxzQkFBYyxDQUFDbkcsSUFBSSxHQUFHOEY7UUFBTyxFQUNqQyxDQUFDO01BQ04sQ0FBQyxNQUFNLElBQUk3RCx5QkFBeUIsQ0FBQ21FLEdBQUcsQ0FBQ2xELFFBQVEsQ0FBQyxFQUFFO1FBQ2hELE1BQU1wRCxZQUFZLENBQUNvQyw0QkFBNEIsQ0FBQ2dCLFFBQVEsRUFBRTtVQUN0RG1ELFdBQVcsRUFBRSxDQUFDUDtRQUNsQixDQUFDLENBQUM7TUFDTjtJQUNKLENBQUMsQ0FBQyxPQUFPdEQsS0FBSyxFQUFFO01BQ1o0QixjQUFNLENBQUM1QixLQUFLLENBQUMsNEJBQTRCLEVBQUVBLEtBQUssQ0FBQztNQUNqRCxNQUFNLElBQUltRCxLQUFLLENBQUMsSUFBQUMsbUJBQUUsRUFBQyxzQ0FBc0MsQ0FBQyxDQUFDO0lBQy9ELENBQUMsU0FBUztNQUNOLE1BQU05QyxjQUFjLENBQUMsQ0FBQztJQUMxQjtFQUNKLENBQUMsRUFDRCxDQUFDaEQsWUFBWSxFQUFFaUMsT0FBTyxFQUFFRSx5QkFBeUIsRUFBRWEsY0FBYyxDQUNyRSxDQUFDO0VBRUQsT0FBTztJQUNIdEMsT0FBTztJQUNQb0Isa0JBQWtCO0lBQ2xCRyxPQUFPO0lBQ1BFLHlCQUF5QjtJQUN6QlgsZUFBZTtJQUNmYyxtQkFBbUI7SUFDbkJJLEtBQUs7SUFDTDhDLHlCQUF5QjtJQUN6QnhDLGNBQWM7SUFDZHlDLGNBQWM7SUFDZE0sb0JBQW9CO0lBQ3BCdkQ7RUFDSixDQUFDO0FBQ0wsQ0FBQztBQUFDdEIsT0FBQSxDQUFBQyxhQUFBLEdBQUFBLGFBQUEiLCJpZ25vcmVMaXN0IjpbXX0=