matrix-react-sdk
Version:
SDK for matrix.org using React
177 lines (161 loc) • 20.6 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Media = void 0;
exports.mediaFromContent = mediaFromContent;
exports.mediaFromMxc = mediaFromMxc;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _MatrixClientPeg = require("../MatrixClientPeg");
var _IMediaEventContent = require("./models/IMediaEventContent");
var _languageHandler = require("../languageHandler");
/*
* Copyright 2024 New Vector Ltd.
* Copyright 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.
*/
// Populate this class with the details of your customisations when copying it.
// Implementation note: The Media class must complete the contract as shown here, though
// the constructor can be whatever is relevant to your implementation. The mediaForX
// functions below create an instance of the Media class and are used throughout the
// project.
/**
* A media object is a representation of a "source media" and an optional
* "thumbnail media", derived from event contents or external sources.
*/
class Media {
// Per above, this constructor signature can be whatever is helpful for you.
constructor(prepared, client) {
(0, _defineProperty2.default)(this, "client", void 0);
this.prepared = prepared;
this.client = client ?? _MatrixClientPeg.MatrixClientPeg.safeGet();
if (!this.client) {
throw new Error("No possible MatrixClient for media resolution. Please provide one or log in.");
}
}
/**
* True if the media appears to be encrypted. Actual file contents may vary.
*/
get isEncrypted() {
return !!this.prepared.file;
}
/**
* The MXC URI of the source media.
*/
get srcMxc() {
return this.prepared.mxc;
}
/**
* The MXC URI of the thumbnail media, if a thumbnail is recorded. Null/undefined
* otherwise.
*/
get thumbnailMxc() {
return this.prepared.thumbnail?.mxc;
}
/**
* Whether or not a thumbnail is recorded for this media.
*/
get hasThumbnail() {
return !!this.thumbnailMxc;
}
/**
* The HTTP URL for the source media.
*/
get srcHttp() {
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.srcMxc, undefined, undefined, undefined, false, true) || null;
}
/**
* The HTTP URL for the thumbnail media (without any specified width, height, etc). Null/undefined
* if no thumbnail media recorded.
*/
get thumbnailHttp() {
if (!this.hasThumbnail) return null;
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.thumbnailMxc, undefined, undefined, undefined, false, true);
}
/**
* Gets the HTTP URL for the thumbnail media with the requested characteristics, if a thumbnail
* is recorded for this media. Returns null/undefined otherwise.
* @param {number} width The desired width of the thumbnail.
* @param {number} height The desired height of the thumbnail.
* @param {"scale"|"crop"} mode The desired thumbnailing mode. Defaults to scale.
* @returns {string} The HTTP URL which points to the thumbnail.
*/
getThumbnailHttp(width, height, mode = "scale") {
if (!this.hasThumbnail) return null;
// scale using the device pixel ratio to keep images clear
width = Math.floor(width * window.devicePixelRatio);
height = Math.floor(height * window.devicePixelRatio);
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.thumbnailMxc, width, height, mode, false, true);
}
/**
* Gets the HTTP URL for a thumbnail of the source media with the requested characteristics.
* @param {number} width The desired width of the thumbnail.
* @param {number} height The desired height of the thumbnail.
* @param {"scale"|"crop"} mode The desired thumbnailing mode. Defaults to scale.
* @returns {string} The HTTP URL which points to the thumbnail.
*/
getThumbnailOfSourceHttp(width, height, mode = "scale") {
// scale using the device pixel ratio to keep images clear
width = Math.floor(width * window.devicePixelRatio);
height = Math.floor(height * window.devicePixelRatio);
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.srcMxc, width, height, mode, false, true);
}
/**
* Creates a square thumbnail of the media. If the media has a thumbnail recorded, that MXC will
* be used, otherwise the source media will be used.
* @param {number} dim The desired width and height.
* @returns {string} An HTTP URL for the thumbnail.
*/
getSquareThumbnailHttp(dim) {
dim = Math.floor(dim * window.devicePixelRatio); // scale using the device pixel ratio to keep images clear
if (this.hasThumbnail) {
return this.getThumbnailHttp(dim, dim, "crop");
}
return this.getThumbnailOfSourceHttp(dim, dim, "crop");
}
/**
* Downloads the source media.
* @returns {Promise<Response>} Resolves to the server's response for chaining.
*/
async downloadSource() {
const src = this.srcHttp;
if (!src) {
throw new _languageHandler.UserFriendlyError("error|download_media");
}
const res = await fetch(src);
if (!res.ok) {
throw (0, _matrix.parseErrorResponse)(res, await res.text());
}
return res;
}
}
/**
* Creates a media object from event content.
* @param {MediaEventContent} content The event content.
* @param {MatrixClient} client? Optional client to use.
* @returns {Media} The media object.
*/
exports.Media = Media;
function mediaFromContent(content, client) {
return new Media((0, _IMediaEventContent.prepEventContentAsMedia)(content), client);
}
/**
* Creates a media object from an MXC URI.
* @param {string} mxc The MXC URI.
* @param {MatrixClient} client? Optional client to use.
* @returns {Media} The media object.
*/
function mediaFromMxc(mxc, client) {
return mediaFromContent({
url: mxc
}, client);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl9NYXRyaXhDbGllbnRQZWciLCJfSU1lZGlhRXZlbnRDb250ZW50IiwiX2xhbmd1YWdlSGFuZGxlciIsIk1lZGlhIiwiY29uc3RydWN0b3IiLCJwcmVwYXJlZCIsImNsaWVudCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsIkVycm9yIiwiaXNFbmNyeXB0ZWQiLCJmaWxlIiwic3JjTXhjIiwibXhjIiwidGh1bWJuYWlsTXhjIiwidGh1bWJuYWlsIiwiaGFzVGh1bWJuYWlsIiwic3JjSHR0cCIsIm14Y1VybFRvSHR0cCIsInVuZGVmaW5lZCIsInRodW1ibmFpbEh0dHAiLCJnZXRUaHVtYm5haWxIdHRwIiwid2lkdGgiLCJoZWlnaHQiLCJtb2RlIiwiTWF0aCIsImZsb29yIiwid2luZG93IiwiZGV2aWNlUGl4ZWxSYXRpbyIsImdldFRodW1ibmFpbE9mU291cmNlSHR0cCIsImdldFNxdWFyZVRodW1ibmFpbEh0dHAiLCJkaW0iLCJkb3dubG9hZFNvdXJjZSIsInNyYyIsIlVzZXJGcmllbmRseUVycm9yIiwicmVzIiwiZmV0Y2giLCJvayIsInBhcnNlRXJyb3JSZXNwb25zZSIsInRleHQiLCJleHBvcnRzIiwibWVkaWFGcm9tQ29udGVudCIsImNvbnRlbnQiLCJwcmVwRXZlbnRDb250ZW50QXNNZWRpYSIsIm1lZGlhRnJvbU14YyIsInVybCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jdXN0b21pc2F0aW9ucy9NZWRpYS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG4gKiBDb3B5cmlnaHQgMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuICpcbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuICogUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiAqL1xuXG5pbXBvcnQgeyBNYXRyaXhDbGllbnQsIHBhcnNlRXJyb3JSZXNwb25zZSwgUmVzaXplTWV0aG9kIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgTWVkaWFFdmVudENvbnRlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvdHlwZXNcIjtcbmltcG9ydCB7IE9wdGlvbmFsIH0gZnJvbSBcIm1hdHJpeC1ldmVudHMtc2RrXCI7XG5cbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IElQcmVwYXJlZE1lZGlhLCBwcmVwRXZlbnRDb250ZW50QXNNZWRpYSB9IGZyb20gXCIuL21vZGVscy9JTWVkaWFFdmVudENvbnRlbnRcIjtcbmltcG9ydCB7IFVzZXJGcmllbmRseUVycm9yIH0gZnJvbSBcIi4uL2xhbmd1YWdlSGFuZGxlclwiO1xuXG4vLyBQb3B1bGF0ZSB0aGlzIGNsYXNzIHdpdGggdGhlIGRldGFpbHMgb2YgeW91ciBjdXN0b21pc2F0aW9ucyB3aGVuIGNvcHlpbmcgaXQuXG5cbi8vIEltcGxlbWVudGF0aW9uIG5vdGU6IFRoZSBNZWRpYSBjbGFzcyBtdXN0IGNvbXBsZXRlIHRoZSBjb250cmFjdCBhcyBzaG93biBoZXJlLCB0aG91Z2hcbi8vIHRoZSBjb25zdHJ1Y3RvciBjYW4gYmUgd2hhdGV2ZXIgaXMgcmVsZXZhbnQgdG8geW91ciBpbXBsZW1lbnRhdGlvbi4gVGhlIG1lZGlhRm9yWFxuLy8gZnVuY3Rpb25zIGJlbG93IGNyZWF0ZSBhbiBpbnN0YW5jZSBvZiB0aGUgTWVkaWEgY2xhc3MgYW5kIGFyZSB1c2VkIHRocm91Z2hvdXQgdGhlXG4vLyBwcm9qZWN0LlxuXG4vKipcbiAqIEEgbWVkaWEgb2JqZWN0IGlzIGEgcmVwcmVzZW50YXRpb24gb2YgYSBcInNvdXJjZSBtZWRpYVwiIGFuZCBhbiBvcHRpb25hbFxuICogXCJ0aHVtYm5haWwgbWVkaWFcIiwgZGVyaXZlZCBmcm9tIGV2ZW50IGNvbnRlbnRzIG9yIGV4dGVybmFsIHNvdXJjZXMuXG4gKi9cbmV4cG9ydCBjbGFzcyBNZWRpYSB7XG4gICAgcHJpdmF0ZSBjbGllbnQ6IE1hdHJpeENsaWVudDtcblxuICAgIC8vIFBlciBhYm92ZSwgdGhpcyBjb25zdHJ1Y3RvciBzaWduYXR1cmUgY2FuIGJlIHdoYXRldmVyIGlzIGhlbHBmdWwgZm9yIHlvdS5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcHJlcGFyZWQ6IElQcmVwYXJlZE1lZGlhLFxuICAgICAgICBjbGllbnQ/OiBNYXRyaXhDbGllbnQsXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY2xpZW50ID0gY2xpZW50ID8/IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgIGlmICghdGhpcy5jbGllbnQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHBvc3NpYmxlIE1hdHJpeENsaWVudCBmb3IgbWVkaWEgcmVzb2x1dGlvbi4gUGxlYXNlIHByb3ZpZGUgb25lIG9yIGxvZyBpbi5cIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcnVlIGlmIHRoZSBtZWRpYSBhcHBlYXJzIHRvIGJlIGVuY3J5cHRlZC4gQWN0dWFsIGZpbGUgY29udGVudHMgbWF5IHZhcnkuXG4gICAgICovXG4gICAgcHVibGljIGdldCBpc0VuY3J5cHRlZCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5wcmVwYXJlZC5maWxlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBNWEMgVVJJIG9mIHRoZSBzb3VyY2UgbWVkaWEuXG4gICAgICovXG4gICAgcHVibGljIGdldCBzcmNNeGMoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJlcGFyZWQubXhjO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBNWEMgVVJJIG9mIHRoZSB0aHVtYm5haWwgbWVkaWEsIGlmIGEgdGh1bWJuYWlsIGlzIHJlY29yZGVkLiBOdWxsL3VuZGVmaW5lZFxuICAgICAqIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHRodW1ibmFpbE14YygpOiBPcHRpb25hbDxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJlcGFyZWQudGh1bWJuYWlsPy5teGM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgYSB0aHVtYm5haWwgaXMgcmVjb3JkZWQgZm9yIHRoaXMgbWVkaWEuXG4gICAgICovXG4gICAgcHVibGljIGdldCBoYXNUaHVtYm5haWwoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMudGh1bWJuYWlsTXhjO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBIVFRQIFVSTCBmb3IgdGhlIHNvdXJjZSBtZWRpYS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHNyY0h0dHAoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLXByb3BlcnRpZXNcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xpZW50Lm14Y1VybFRvSHR0cCh0aGlzLnNyY014YywgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgZmFsc2UsIHRydWUpIHx8IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIEhUVFAgVVJMIGZvciB0aGUgdGh1bWJuYWlsIG1lZGlhICh3aXRob3V0IGFueSBzcGVjaWZpZWQgd2lkdGgsIGhlaWdodCwgZXRjKS4gTnVsbC91bmRlZmluZWRcbiAgICAgKiBpZiBubyB0aHVtYm5haWwgbWVkaWEgcmVjb3JkZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCB0aHVtYm5haWxIdHRwKCk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICBpZiAoIXRoaXMuaGFzVGh1bWJuYWlsKSByZXR1cm4gbnVsbDtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtcHJvcGVydGllc1xuICAgICAgICByZXR1cm4gdGhpcy5jbGllbnQubXhjVXJsVG9IdHRwKHRoaXMudGh1bWJuYWlsTXhjISwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgZmFsc2UsIHRydWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIEhUVFAgVVJMIGZvciB0aGUgdGh1bWJuYWlsIG1lZGlhIHdpdGggdGhlIHJlcXVlc3RlZCBjaGFyYWN0ZXJpc3RpY3MsIGlmIGEgdGh1bWJuYWlsXG4gICAgICogaXMgcmVjb3JkZWQgZm9yIHRoaXMgbWVkaWEuIFJldHVybnMgbnVsbC91bmRlZmluZWQgb3RoZXJ3aXNlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCBUaGUgZGVzaXJlZCB3aWR0aCBvZiB0aGUgdGh1bWJuYWlsLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgVGhlIGRlc2lyZWQgaGVpZ2h0IG9mIHRoZSB0aHVtYm5haWwuXG4gICAgICogQHBhcmFtIHtcInNjYWxlXCJ8XCJjcm9wXCJ9IG1vZGUgVGhlIGRlc2lyZWQgdGh1bWJuYWlsaW5nIG1vZGUuIERlZmF1bHRzIHRvIHNjYWxlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBIVFRQIFVSTCB3aGljaCBwb2ludHMgdG8gdGhlIHRodW1ibmFpbC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VGh1bWJuYWlsSHR0cCh3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlciwgbW9kZTogUmVzaXplTWV0aG9kID0gXCJzY2FsZVwiKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIGlmICghdGhpcy5oYXNUaHVtYm5haWwpIHJldHVybiBudWxsO1xuICAgICAgICAvLyBzY2FsZSB1c2luZyB0aGUgZGV2aWNlIHBpeGVsIHJhdGlvIHRvIGtlZXAgaW1hZ2VzIGNsZWFyXG4gICAgICAgIHdpZHRoID0gTWF0aC5mbG9vcih3aWR0aCAqIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKTtcbiAgICAgICAgaGVpZ2h0ID0gTWF0aC5mbG9vcihoZWlnaHQgKiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyk7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLXByb3BlcnRpZXNcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xpZW50Lm14Y1VybFRvSHR0cCh0aGlzLnRodW1ibmFpbE14YyEsIHdpZHRoLCBoZWlnaHQsIG1vZGUsIGZhbHNlLCB0cnVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBIVFRQIFVSTCBmb3IgYSB0aHVtYm5haWwgb2YgdGhlIHNvdXJjZSBtZWRpYSB3aXRoIHRoZSByZXF1ZXN0ZWQgY2hhcmFjdGVyaXN0aWNzLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCBUaGUgZGVzaXJlZCB3aWR0aCBvZiB0aGUgdGh1bWJuYWlsLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgVGhlIGRlc2lyZWQgaGVpZ2h0IG9mIHRoZSB0aHVtYm5haWwuXG4gICAgICogQHBhcmFtIHtcInNjYWxlXCJ8XCJjcm9wXCJ9IG1vZGUgVGhlIGRlc2lyZWQgdGh1bWJuYWlsaW5nIG1vZGUuIERlZmF1bHRzIHRvIHNjYWxlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBIVFRQIFVSTCB3aGljaCBwb2ludHMgdG8gdGhlIHRodW1ibmFpbC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VGh1bWJuYWlsT2ZTb3VyY2VIdHRwKHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBtb2RlOiBSZXNpemVNZXRob2QgPSBcInNjYWxlXCIpOiBzdHJpbmcgfCBudWxsIHtcbiAgICAgICAgLy8gc2NhbGUgdXNpbmcgdGhlIGRldmljZSBwaXhlbCByYXRpbyB0byBrZWVwIGltYWdlcyBjbGVhclxuICAgICAgICB3aWR0aCA9IE1hdGguZmxvb3Iod2lkdGggKiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyk7XG4gICAgICAgIGhlaWdodCA9IE1hdGguZmxvb3IoaGVpZ2h0ICogd2luZG93LmRldmljZVBpeGVsUmF0aW8pO1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1wcm9wZXJ0aWVzXG4gICAgICAgIHJldHVybiB0aGlzLmNsaWVudC5teGNVcmxUb0h0dHAodGhpcy5zcmNNeGMsIHdpZHRoLCBoZWlnaHQsIG1vZGUsIGZhbHNlLCB0cnVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgc3F1YXJlIHRodW1ibmFpbCBvZiB0aGUgbWVkaWEuIElmIHRoZSBtZWRpYSBoYXMgYSB0aHVtYm5haWwgcmVjb3JkZWQsIHRoYXQgTVhDIHdpbGxcbiAgICAgKiBiZSB1c2VkLCBvdGhlcndpc2UgdGhlIHNvdXJjZSBtZWRpYSB3aWxsIGJlIHVzZWQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGRpbSBUaGUgZGVzaXJlZCB3aWR0aCBhbmQgaGVpZ2h0LlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEFuIEhUVFAgVVJMIGZvciB0aGUgdGh1bWJuYWlsLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRTcXVhcmVUaHVtYm5haWxIdHRwKGRpbTogbnVtYmVyKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIGRpbSA9IE1hdGguZmxvb3IoZGltICogd2luZG93LmRldmljZVBpeGVsUmF0aW8pOyAvLyBzY2FsZSB1c2luZyB0aGUgZGV2aWNlIHBpeGVsIHJhdGlvIHRvIGtlZXAgaW1hZ2VzIGNsZWFyXG4gICAgICAgIGlmICh0aGlzLmhhc1RodW1ibmFpbCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0VGh1bWJuYWlsSHR0cChkaW0sIGRpbSwgXCJjcm9wXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmdldFRodW1ibmFpbE9mU291cmNlSHR0cChkaW0sIGRpbSwgXCJjcm9wXCIpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERvd25sb2FkcyB0aGUgc291cmNlIG1lZGlhLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFJlc3BvbnNlPn0gUmVzb2x2ZXMgdG8gdGhlIHNlcnZlcidzIHJlc3BvbnNlIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZG93bmxvYWRTb3VyY2UoKTogUHJvbWlzZTxSZXNwb25zZT4ge1xuICAgICAgICBjb25zdCBzcmMgPSB0aGlzLnNyY0h0dHA7XG4gICAgICAgIGlmICghc3JjKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVXNlckZyaWVuZGx5RXJyb3IoXCJlcnJvcnxkb3dubG9hZF9tZWRpYVwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaChzcmMpO1xuICAgICAgICBpZiAoIXJlcy5vaykge1xuICAgICAgICAgICAgdGhyb3cgcGFyc2VFcnJvclJlc3BvbnNlKHJlcywgYXdhaXQgcmVzLnRleHQoKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG1lZGlhIG9iamVjdCBmcm9tIGV2ZW50IGNvbnRlbnQuXG4gKiBAcGFyYW0ge01lZGlhRXZlbnRDb250ZW50fSBjb250ZW50IFRoZSBldmVudCBjb250ZW50LlxuICogQHBhcmFtIHtNYXRyaXhDbGllbnR9IGNsaWVudD8gT3B0aW9uYWwgY2xpZW50IHRvIHVzZS5cbiAqIEByZXR1cm5zIHtNZWRpYX0gVGhlIG1lZGlhIG9iamVjdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lZGlhRnJvbUNvbnRlbnQoY29udGVudDogUGFydGlhbDxNZWRpYUV2ZW50Q29udGVudD4sIGNsaWVudD86IE1hdHJpeENsaWVudCk6IE1lZGlhIHtcbiAgICByZXR1cm4gbmV3IE1lZGlhKHByZXBFdmVudENvbnRlbnRBc01lZGlhKGNvbnRlbnQpLCBjbGllbnQpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBtZWRpYSBvYmplY3QgZnJvbSBhbiBNWEMgVVJJLlxuICogQHBhcmFtIHtzdHJpbmd9IG14YyBUaGUgTVhDIFVSSS5cbiAqIEBwYXJhbSB7TWF0cml4Q2xpZW50fSBjbGllbnQ/IE9wdGlvbmFsIGNsaWVudCB0byB1c2UuXG4gKiBAcmV0dXJucyB7TWVkaWF9IFRoZSBtZWRpYSBvYmplY3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZWRpYUZyb21NeGMobXhjPzogc3RyaW5nLCBjbGllbnQ/OiBNYXRyaXhDbGllbnQpOiBNZWRpYSB7XG4gICAgcmV0dXJuIG1lZGlhRnJvbUNvbnRlbnQoeyB1cmw6IG14YyB9LCBjbGllbnQpO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBSUEsSUFBQUMsZ0JBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLG1CQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxnQkFBQSxHQUFBSCxPQUFBO0FBZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBVUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDTyxNQUFNSSxLQUFLLENBQUM7RUFHZjtFQUNPQyxXQUFXQSxDQUNOQyxRQUF3QixFQUNoQ0MsTUFBcUIsRUFDdkI7SUFBQSxJQUFBQyxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsS0FGVUgsUUFBd0IsR0FBeEJBLFFBQXdCO0lBR2hDLElBQUksQ0FBQ0MsTUFBTSxHQUFHQSxNQUFNLElBQUlHLGdDQUFlLENBQUNDLE9BQU8sQ0FBQyxDQUFDO0lBQ2pELElBQUksQ0FBQyxJQUFJLENBQUNKLE1BQU0sRUFBRTtNQUNkLE1BQU0sSUFBSUssS0FBSyxDQUFDLDhFQUE4RSxDQUFDO0lBQ25HO0VBQ0o7O0VBRUE7QUFDSjtBQUNBO0VBQ0ksSUFBV0MsV0FBV0EsQ0FBQSxFQUFZO0lB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