UNPKG

ngx-object-diff

Version:

An Angular 2+ library to compare and show object differences.

552 lines 38.9 kB
/** * @fileoverview added by tsickle * Generated from: lib/ngx-object-diff.service.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Injectable, SecurityContext } from '@angular/core'; import { DomSanitizer } from "@angular/platform-browser"; import * as i0 from "@angular/core"; import * as i1 from "@angular/platform-browser"; var NgxObjectDiffService = /** @class */ (function () { function NgxObjectDiffService(sanitizer) { this.sanitizer = sanitizer; this.openChar = '{'; this.closeChar = '}'; } /* service methods */ /** * @param char */ /* service methods */ /** * @param {?} char * @return {?} */ NgxObjectDiffService.prototype.setOpenChar = /* service methods */ /** * @param {?} char * @return {?} */ function (char) { this.openChar = char; }; /** * @param char */ /** * @param {?} char * @return {?} */ NgxObjectDiffService.prototype.setCloseChar = /** * @param {?} char * @return {?} */ function (char) { this.closeChar = char; }; /** * diff between object a and b * @param a * @param b * @param shallow * @param isOwn * @return */ /** * diff between object a and b * @param {?} a * @param {?} b * @param {?=} shallow * @param {?=} isOwn * @return {?} */ NgxObjectDiffService.prototype.diff = /** * diff between object a and b * @param {?} a * @param {?} b * @param {?=} shallow * @param {?=} isOwn * @return {?} */ function (a, b, shallow, isOwn) { if (a === b) { return this.equalObj(a); } /** @type {?} */ var diffValue = {}; /** @type {?} */ var equal = true; for (var key in a) { if ((!isOwn && key in b) || (isOwn && typeof b != 'undefined' && b.hasOwnProperty(key))) { if (a[key] === b[key]) { diffValue[key] = this.equalObj(a[key]); } else { if (!shallow && this.isValidAttr(a[key], b[key])) { /** @type {?} */ var valueDiff = this.diff(a[key], b[key], shallow, isOwn); if (valueDiff.changed == 'equal') { diffValue[key] = this.equalObj(a[key]); } else { equal = false; diffValue[key] = valueDiff; } } else { equal = false; diffValue[key] = { changed: 'primitive change', removed: a[key], added: b[key] }; } } } else { equal = false; diffValue[key] = { changed: 'removed', value: a[key] }; } } for (var key in b) { if ((!isOwn && !(key in a)) || (isOwn && typeof a != 'undefined' && !a.hasOwnProperty(key))) { equal = false; diffValue[key] = { changed: 'added', value: b[key] }; } } if (equal) { return this.equalObj(a); } else { return { changed: 'object change', value: diffValue }; } }; /** * compare and build the difference of two objects taking only its own properties into account * @param a * @param b * @param shallow */ /** * compare and build the difference of two objects taking only its own properties into account * @param {?} a * @param {?} b * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.diffOwnProperties = /** * compare and build the difference of two objects taking only its own properties into account * @param {?} a * @param {?} b * @param {?=} shallow * @return {?} */ function (a, b, shallow) { return this.diff(a, b, shallow, true); }; /** * Convert to a readable xml/html Json structure * @param changes * @return * @param shallow */ /** * Convert to a readable xml/html Json structure * @param {?} changes * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.toJsonView = /** * Convert to a readable xml/html Json structure * @param {?} changes * @param {?=} shallow * @return {?} */ function (changes, shallow) { return this.formatToJsonXMLString(changes, shallow); }; /** * Convert to a readable xml/html Json structure * @return * @param obj * @param shallow */ /** * Convert to a readable xml/html Json structure * @param {?} object * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.objToJsonView = /** * Convert to a readable xml/html Json structure * @param {?} object * @param {?=} shallow * @return {?} */ function (object, shallow) { return this.formatObjToJsonXMLString(object, shallow); }; /** * Convert to a readable xml/html Json structure * @param changes * @return * @param shallow */ /** * Convert to a readable xml/html Json structure * @param {?} changes * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.toJsonDiffView = /** * Convert to a readable xml/html Json structure * @param {?} changes * @param {?=} shallow * @return {?} */ function (changes, shallow) { return this.formatChangesToXMLString(changes, shallow); }; /** * Convert to a readable xml/html Json structure * Convert to a readable xml/html Json structure * @return * @param obj * @param shallow */ /** * Convert to a readable xml/html Json structure * Convert to a readable xml/html Json structure * @private * @param {?} obj * @param {?} shallow * @return {?} */ NgxObjectDiffService.prototype.formatObjToJsonXMLString = /** * Convert to a readable xml/html Json structure * Convert to a readable xml/html Json structure * @private * @param {?} obj * @param {?} shallow * @return {?} */ function (obj, shallow) { return this.sanitizer.bypassSecurityTrustHtml(this.inspect(obj, shallow)); }; /** * Convert to a readable xml/html Json structure * @param changes * @return * @param shallow */ /** * Convert to a readable xml/html Json structure * @private * @param {?} changes * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.formatToJsonXMLString = /** * Convert to a readable xml/html Json structure * @private * @param {?} changes * @param {?=} shallow * @return {?} */ function (changes, shallow) { /** @type {?} */ var properties = []; /** @type {?} */ var diff = changes.value; if (changes.changed == 'equal') { return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml(this.inspect(diff, shallow))); } for (var key in diff) { properties.push(this.formatChange(key, diff[key], shallow)); } return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml('<span>' + this.openChar + '</span>\n<div class="diff-level">' + properties.join('<span>,</span>\n') + '\n</div><span>' + this.closeChar + '</span>')); }; /** * @private * @param {?} changes * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.formatChangesToXMLString = /** * @private * @param {?} changes * @param {?=} shallow * @return {?} */ function (changes, shallow) { /** @type {?} */ var properties = []; if (changes.changed == 'equal') { return ''; } /** @type {?} */ var diff = changes.value; for (var key in diff) { /** @type {?} */ var changed = diff[key].changed; if (changed !== 'equal') properties.push(this.formatChange(key, diff[key], shallow, true)); } return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml('<span>' + this.openChar + '</span>\n<div class="diff-level">' + properties.join('<span>,</span>\n') + '\n</div><span>' + this.closeChar + '</span>')); }; /** * @param key * @param diffItem * @returns * @param shallow * @param diffOnly */ /** * @private * @param {?} key * @param {?} diffItem * @param {?} shallow * @param {?=} diffOnly * @return {?} */ NgxObjectDiffService.prototype.formatChange = /** * @private * @param {?} key * @param {?} diffItem * @param {?} shallow * @param {?=} diffOnly * @return {?} */ function (key, diffItem, shallow, diffOnly) { /** @type {?} */ var changed = diffItem.changed; /** @type {?} */ var property; switch (changed) { case 'equal': property = (this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value)); break; case 'removed': property = ('<del class="diff">' + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value) + '</del>'); break; case 'added': property = ('<ins class="diff">' + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value) + '</ins>'); break; case 'primitive change': /** @type {?} */ var prefix = this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>'; property = ('<del class="diff diff-key">' + prefix + this.inspect(diffItem.removed) + '</del><span>,</span>\n' + '<ins class="diff diff-key">' + prefix + this.inspect(diffItem.added) + '</ins>'); break; case 'object change': property = shallow ? '' : (this.stringifyObjectKey(key) + '<span>: </span>' + (diffOnly ? this.formatChangesToXMLString(diffItem) : this.formatToJsonXMLString(diffItem))); break; } return property; }; /** * @param obj * @return * @param shallow */ /** * @private * @param {?} obj * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype.inspect = /** * @private * @param {?} obj * @param {?=} shallow * @return {?} */ function (obj, shallow) { return this._inspect('', obj, shallow); }; /** * @param accumulator * @param obj * @see http://jsperf.com/continuation-passing-style/3 * @return * @param shallow */ /** * @see http://jsperf.com/continuation-passing-style/3 * @private * @param {?} accumulator * @param {?} obj * @param {?=} shallow * @return {?} */ NgxObjectDiffService.prototype._inspect = /** * @see http://jsperf.com/continuation-passing-style/3 * @private * @param {?} accumulator * @param {?} obj * @param {?=} shallow * @return {?} */ function (accumulator, obj, shallow) { switch (typeof obj) { case 'object': if (!obj) { accumulator += 'null'; break; } if (shallow) { accumulator += '[object]'; break; } /** @type {?} */ var keys = Object.keys(obj); /** @type {?} */ var length_1 = keys.length; if (length_1 === 0) { accumulator += '<span>' + this.openChar + this.closeChar + '</span>'; } else { accumulator += '<span>' + this.openChar + '</span>\n<div class="diff-level">'; for (var i = 0; i < length_1; i++) { /** @type {?} */ var key = keys[i]; accumulator = this._inspect(accumulator + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>', obj[key]); if (i < length_1 - 1) { accumulator += '<span>,</span>\n'; } } accumulator += '\n</div><span>' + this.closeChar + '</span>'; } break; case 'string': accumulator += JSON.stringify(this.escapeHTML(obj)); break; case 'undefined': accumulator += 'undefined'; break; default: accumulator += this.escapeHTML(String(obj)); break; } return accumulator; }; /** * @param key * @return */ /** * @private * @param {?} key * @return {?} */ NgxObjectDiffService.prototype.stringifyObjectKey = /** * @private * @param {?} key * @return {?} */ function (key) { return /^[a-z0-9_$]*$/i.test(key) ? key : JSON.stringify(key); }; /** * @param string * @return */ /** * @private * @param {?} string * @return {?} */ NgxObjectDiffService.prototype.escapeHTML = /** * @private * @param {?} string * @return {?} */ function (string) { return string.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }; /** * @param obj * @returns */ /** * @private * @param {?} obj * @return {?} */ NgxObjectDiffService.prototype.equalObj = /** * @private * @param {?} obj * @return {?} */ function (obj) { return { changed: 'equal', value: obj }; }; /** * @param a * @param b * @returns */ /** * @private * @param {?} a * @param {?} b * @return {?} */ NgxObjectDiffService.prototype.isValidAttr = /** * @private * @param {?} a * @param {?} b * @return {?} */ function (a, b) { /** @type {?} */ var typeA = typeof a; /** @type {?} */ var typeB = typeof b; return (a && b && (typeA == 'object' || typeA == 'function') && (typeB == 'object' || typeB == 'function')); }; NgxObjectDiffService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ NgxObjectDiffService.ctorParameters = function () { return [ { type: DomSanitizer } ]; }; /** @nocollapse */ NgxObjectDiffService.ngInjectableDef = i0.ɵɵdefineInjectable({ factory: function NgxObjectDiffService_Factory() { return new NgxObjectDiffService(i0.ɵɵinject(i1.DomSanitizer)); }, token: NgxObjectDiffService, providedIn: "root" }); return NgxObjectDiffService; }()); export { NgxObjectDiffService }; if (false) { /** * @type {?} * @private */ NgxObjectDiffService.prototype.openChar; /** * @type {?} * @private */ NgxObjectDiffService.prototype.closeChar; /** * @type {?} * @private */ NgxObjectDiffService.prototype.sanitizer; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW9iamVjdC1kaWZmLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtb2JqZWN0LWRpZmYvIiwic291cmNlcyI6WyJsaWIvbmd4LW9iamVjdC1kaWZmLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBQUMsVUFBVSxFQUFFLGVBQWUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUMxRCxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sMkJBQTJCLENBQUM7OztBQUV2RDtJQVFFLDhCQUFvQixTQUF1QjtRQUF2QixjQUFTLEdBQVQsU0FBUyxDQUFjO1FBSG5DLGFBQVEsR0FBRyxHQUFHLENBQUM7UUFDZixjQUFTLEdBQUcsR0FBRyxDQUFDO0lBRXVCLENBQUM7SUFFaEQscUJBQXFCO0lBRXJCOztPQUVHOzs7Ozs7SUFDSSwwQ0FBVzs7Ozs7SUFBbEIsVUFBbUIsSUFBWTtRQUM3QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7Ozs7O0lBQ0ksMkNBQVk7Ozs7SUFBbkIsVUFBb0IsSUFBWTtRQUM5QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztJQUN4QixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRzs7Ozs7Ozs7O0lBQ0ksbUNBQUk7Ozs7Ozs7O0lBQVgsVUFBWSxDQUFTLEVBQUUsQ0FBUyxFQUFFLE9BQWlCLEVBQUUsS0FBZTtRQUVsRSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDWCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDekI7O1lBRUcsU0FBUyxHQUFHLEVBQUU7O1lBQ2QsS0FBSyxHQUFHLElBQUk7UUFFaEIsS0FBSyxJQUFJLEdBQUcsSUFBSSxDQUFDLEVBQUU7WUFDakIsSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLENBQUMsSUFB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QUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBRUQ7OztPQUdHOzs7Ozs7SUFDSyx5Q0FBVTs7Ozs7SUFBbEIsVUFBbUIsTUFBTTtRQUN2QixPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNuRixDQUFDO0lBRUQ7OztPQUdHOzs7Ozs7SUFDSyx1Q0FBUTs7Ozs7SUFBaEIsVUFBaUIsR0FBRztRQUNsQixPQUFPO1lBQ0wsT0FBTyxFQUFFLE9BQU87WUFDaEIsS0FBSyxFQUFFLEdBQUc7U0FDWCxDQUFBO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7Ozs7Ozs7SUFDSywwQ0FBVzs7Ozs7O0lBQW5CLFVBQW9CLENBQVMsRUFBRSxDQUFTOztZQUNsQyxLQUFLLEdBQUcsT0FBTyxDQUFDOztZQUNoQixLQUFLLEdBQUcsT0FBTyxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLFFBQVEsSUFBSSxLQUFLLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksUUFBUSxJQUFJLEtBQUssSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzlHLENBQUM7O2dCQXJVRixVQUFVLFNBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25COzs7O2dCQUpPLFlBQVk7OzsrQkFEcEI7Q0F5VUMsQUF0VUQsSUFzVUM7U0FuVVksb0JBQW9COzs7Ozs7SUFFL0Isd0NBQXVCOzs7OztJQUN2Qix5Q0FBd0I7Ozs7O0lBRVoseUNBQStCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJbmplY3RhYmxlLCBTZWN1cml0eUNvbnRleHR9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtEb21TYW5pdGl6ZXJ9IGZyb20gXCJAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyXCI7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5neE9iamVjdERpZmZTZXJ2aWNlIHtcblxuICBwcml2YXRlIG9wZW5DaGFyID0gJ3snO1xuICBwcml2YXRlIGNsb3NlQ2hhciA9ICd9JztcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNhbml0aXplcjogRG9tU2FuaXRpemVyKSB7IH1cblxuICAvKiBzZXJ2aWNlIG1ldGhvZHMgKi9cblxuICAvKipcbiAgICogQHBhcmFtIGNoYXJcbiAgICovXG4gIHB1YmxpYyBzZXRPcGVuQ2hhcihjaGFyOiBzdHJpbmcpIHtcbiAgICB0aGlzLm9wZW5DaGFyID0gY2hhcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gY2hhclxuICAgKi9cbiAgcHVibGljIHNldENsb3NlQ2hhcihjaGFyOiBzdHJpbmcpIHtcbiAgICB0aGlzLmNsb3NlQ2hhciA9IGNoYXI7XG4gIH1cblxuICAvKipcbiAgICogZGlmZiBiZXR3ZWVuIG9iamVjdCBhIGFuZCBiXG4gICAqIEBwYXJhbSBhXG4gICAqIEBwYXJhbSBiXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqIEBwYXJhbSBpc093blxuICAgKiBAcmV0dXJuXG4gICAqL1xuICBwdWJsaWMgZGlmZihhOiBPYmplY3QsIGI6IE9iamVjdCwgc2hhbGxvdz86IGJvb2xlYW4sIGlzT3duPzogYm9vbGVhbikge1xuXG4gICAgaWYgKGEgPT09IGIpIHtcbiAgICAgIHJldHVybiB0aGlzLmVxdWFsT2JqKGEpO1xuICAgIH1cblxuICAgIGxldCBkaWZmVmFsdWUgPSB7fTtcbiAgICBsZXQgZXF1YWwgPSB0cnVlO1xuXG4gICAgZm9yIChsZXQga2V5IGluIGEpIHtcbiAgICAgIGlmICgoIWlzT3duICYmIGtleSBpbiBiKSB8fCAoaXNPd24gJiYgdHlwZW9mIGIgIT0gJ3VuZGVmaW5lZCcgJiYgYi5oYXNPd25Qcm9wZXJ0eShrZXkpKSkge1xuICAgICAgICBpZiAoYVtrZXldID09PSBiW2tleV0pIHtcbiAgICAgICAgICBkaWZmVmFsdWVba2V5XSA9IHRoaXMuZXF1YWxPYmooYVtrZXldKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAoIXNoYWxsb3cgJiYgdGhpcy5pc1ZhbGlkQXR0cihhW2tleV0sIGJba2V5XSkpIHtcbiAgICAgICAgICAgIGxldCB2YWx1ZURpZmYgPSB0aGlzLmRpZmYoYVtrZXldLCBiW2tleV0sIHNoYWxsb3csIGlzT3duKTtcbiAgICAgICAgICAgIGlmICh2YWx1ZURpZmYuY2hhbmdlZCA9PSAnZXF1YWwnKSB7XG4gICAgICAgICAgICAgIGRpZmZWYWx1ZVtrZXldID0gdGhpcy5lcXVhbE9iaihhW2tleV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZXF1YWwgPSBmYWxzZTtcbiAgICAgICAgICAgICAgZGlmZlZhbHVlW2tleV0gPSB2YWx1ZURpZmY7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVxdWFsID0gZmFsc2U7XG4gICAgICAgICAgICBkaWZmVmFsdWVba2V5XSA9IHtcbiAgICAgICAgICAgICAgY2hhbmdlZDogJ3ByaW1pdGl2ZSBjaGFuZ2UnLFxuICAgICAgICAgICAgICByZW1vdmVkOiBhW2tleV0sXG4gICAgICAgICAgICAgIGFkZGVkOiBiW2tleV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVxdWFsID0gZmFsc2U7XG4gICAgICAgIGRpZmZWYWx1ZVtrZXldID0ge1xuICAgICAgICAgIGNoYW5nZWQ6ICdyZW1vdmVkJyxcbiAgICAgICAgICB2YWx1ZTogYVtrZXldXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGxldCBrZXkgaW4gYikge1xuICAgICAgaWYgKCghaXNPd24gJiYgIShrZXkgaW4gYSkpIHx8IChpc093biAmJiB0eXBlb2YgYSAhPSAndW5kZWZpbmVkJyAmJiAhYS5oYXNPd25Qcm9wZXJ0eShrZXkpKSkge1xuICAgICAgICBlcXVhbCA9IGZhbHNlO1xuICAgICAgICBkaWZmVmFsdWVba2V5XSA9IHtcbiAgICAgICAgICBjaGFuZ2VkOiAnYWRkZWQnLFxuICAgICAgICAgIHZhbHVlOiBiW2tleV1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChlcXVhbCkge1xuICAgICAgcmV0dXJuIHRoaXMuZXF1YWxPYmooYSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNoYW5nZWQ6ICdvYmplY3QgY2hhbmdlJyxcbiAgICAgICAgdmFsdWU6IGRpZmZWYWx1ZVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBjb21wYXJlIGFuZCBidWlsZCB0aGUgZGlmZmVyZW5jZSBvZiB0d28gb2JqZWN0cyB0YWtpbmcgb25seSBpdHMgb3duIHByb3BlcnRpZXMgaW50byBhY2NvdW50XG4gICAqIEBwYXJhbSBhXG4gICAqIEBwYXJhbSBiXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqL1xuICBwdWJsaWMgZGlmZk93blByb3BlcnRpZXMoYTogT2JqZWN0LCBiOiBPYmplY3QsIHNoYWxsb3c/OiBib29sZWFuKSB7XG4gICAgcmV0dXJuIHRoaXMuZGlmZihhLCBiLCBzaGFsbG93LCB0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRvIGEgcmVhZGFibGUgeG1sL2h0bWwgSnNvbiBzdHJ1Y3R1cmVcbiAgICogQHBhcmFtIGNoYW5nZXNcbiAgICogQHJldHVyblxuICAgKiBAcGFyYW0gc2hhbGxvd1xuICAgKi9cbiAgcHVibGljIHRvSnNvblZpZXcoY2hhbmdlcywgc2hhbGxvdz86Ym9vbGVhbikge1xuICAgIHJldHVybiB0aGlzLmZvcm1hdFRvSnNvblhNTFN0cmluZyhjaGFuZ2VzLCBzaGFsbG93KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRvIGEgcmVhZGFibGUgeG1sL2h0bWwgSnNvbiBzdHJ1Y3R1cmVcbiAgICogQHJldHVyblxuICAgKiBAcGFyYW0gb2JqXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqL1xuICBwdWJsaWMgb2JqVG9Kc29uVmlldyhvYmplY3Qsc2hhbGxvdz86Ym9vbGVhbik6IE9iamVjdHtcbiAgICByZXR1cm4gdGhpcy5mb3JtYXRPYmpUb0pzb25YTUxTdHJpbmcob2JqZWN0LHNoYWxsb3cpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgdG8gYSByZWFkYWJsZSB4bWwvaHRtbCBKc29uIHN0cnVjdHVyZVxuICAgKiBAcGFyYW0gY2hhbmdlc1xuICAgKiBAcmV0dXJuXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqL1xuICBwdWJsaWMgdG9Kc29uRGlmZlZpZXcoY2hhbmdlcywgc2hhbGxvdz86IGJvb2xlYW4pIDogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5mb3JtYXRDaGFuZ2VzVG9YTUxTdHJpbmcoY2hhbmdlcywgc2hhbGxvdyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCB0byBhIHJlYWRhYmxlIHhtbC9odG1sIEpzb24gc3RydWN0dXJlXG4gICAqIENvbnZlcnQgdG8gYSByZWFkYWJsZSB4bWwvaHRtbCBKc29uIHN0cnVjdHVyZVxuICAgKiBAcmV0dXJuXG4gICAqIEBwYXJhbSBvYmpcbiAgICogQHBhcmFtIHNoYWxsb3dcbiAgICovXG4gIHByaXZhdGUgZm9ybWF0T2JqVG9Kc29uWE1MU3RyaW5nKG9iaiwgc2hhbGxvdykge1xuICAgIHJldHVybiB0aGlzLnNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0SHRtbCh0aGlzLmluc3BlY3Qob2JqLCBzaGFsbG93KSk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCB0byBhIHJlYWRhYmxlIHhtbC9odG1sIEpzb24gc3RydWN0dXJlXG4gICAqIEBwYXJhbSBjaGFuZ2VzXG4gICAqIEByZXR1cm5cbiAgICogQHBhcmFtIHNoYWxsb3dcbiAgICovXG4gIHByaXZhdGUgZm9ybWF0VG9Kc29uWE1MU3RyaW5nKGNoYW5nZXMsIHNoYWxsb3c/OmJvb2xlYW4pIHtcbiAgICBsZXQgcHJvcGVydGllcyA9IFtdO1xuXG4gICAgbGV0IGRpZmYgPSBjaGFuZ2VzLnZhbHVlO1xuICAgIGlmIChjaGFuZ2VzLmNoYW5nZWQgPT0gJ2VxdWFsJykge1xuICAgICAgcmV0dXJuIHRoaXMuc2FuaXRpemVyLnNhbml0aXplKFNlY3VyaXR5Q29udGV4dC5IVE1MLHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RIdG1sKHRoaXMuaW5zcGVjdChkaWZmLCBzaGFsbG93KSkpO1xuICAgIH1cblxuICAgIGZvciAobGV0IGtleSBpbiBkaWZmKSB7XG4gICAgICBwcm9wZXJ0aWVzLnB1c2godGhpcy5mb3JtYXRDaGFuZ2Uoa2V5LCBkaWZmW2tleV0sIHNoYWxsb3cpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zYW5pdGl6ZXIuc2FuaXRpemUoU2VjdXJpdHlDb250ZXh0LkhUTUwsdGhpcy5zYW5pdGl6ZXIuYnlwYXNzU2VjdXJpdHlUcnVzdEh0bWwoJzxzcGFuPicgKyB0aGlzLm9wZW5DaGFyICsgJzwvc3Bhbj5cXG48ZGl2IGNsYXNzPVwiZGlmZi1sZXZlbFwiPicgKyBwcm9wZXJ0aWVzLmpvaW4oJzxzcGFuPiw8L3NwYW4+XFxuJykgKyAnXFxuPC9kaXY+PHNwYW4+JyArIHRoaXMuY2xvc2VDaGFyICsgJzwvc3Bhbj4nKSk7XG5cbiAgfVxuXG5cbiAgcHJpdmF0ZSBmb3JtYXRDaGFuZ2VzVG9YTUxTdHJpbmcoY2hhbmdlcywgc2hhbGxvdz86IGJvb2xlYW4pIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IFtdO1xuXG4gICAgaWYgKGNoYW5nZXMuY2hhbmdlZCA9PSAnZXF1YWwnKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgdmFyIGRpZmYgPSBjaGFuZ2VzLnZhbHVlO1xuXG4gICAgZm9yICh2YXIga2V5IGluIGRpZmYpIHtcbiAgICAgIHZhciBjaGFuZ2VkID0gZGlmZltrZXldLmNoYW5nZWQ7XG4gICAgICBpZiAoY2hhbmdlZCAhPT0gJ2VxdWFsJylcbiAgICAgICAgcHJvcGVydGllcy5wdXNoKHRoaXMuZm9ybWF0Q2hhbmdlKGtleSwgZGlmZltrZXldLCBzaGFsbG93LCB0cnVlKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuc2FuaXRpemVyLnNhbml0aXplKFNlY3VyaXR5Q29udGV4dC5IVE1MLHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RIdG1sKCc8c3Bhbj4nICsgdGhpcy5vcGVuQ2hhciArICc8L3NwYW4+XFxuPGRpdiBjbGFzcz1cImRpZmYtbGV2ZWxcIj4nICsgcHJvcGVydGllcy5qb2luKCc8c3Bhbj4sPC9zcGFuPlxcbicpICsgJ1xcbjwvZGl2PjxzcGFuPicgKyB0aGlzLmNsb3NlQ2hhciArICc8L3NwYW4+JykpO1xuXG4gIH1cblxuXG4gIC8qKlxuICAgKiBAcGFyYW0ga2V5XG4gICAqIEBwYXJhbSBkaWZmSXRlbVxuICAgKiBAcmV0dXJuc1xuICAgKiBAcGFyYW0gc2hhbGxvd1xuICAgKiBAcGFyYW0gZGlmZk9ubHlcbiAgICovXG4gIHByaXZhdGUgZm9ybWF0Q2hhbmdlKGtleSwgZGlmZkl0ZW0sIHNoYWxsb3c6IGJvb2xlYW4sIGRpZmZPbmx5Pykge1xuICAgIHZhciBjaGFuZ2VkID0gZGlmZkl0ZW0uY2hhbmdlZDtcbiAgICB2YXIgcHJvcGVydHk7XG4gICAgc3dpdGNoIChjaGFuZ2VkKSB7XG4gICAgICBjYXNlICdlcXVhbCc6XG4gICAgICAgIHByb3BlcnR5ID0gKHRoaXMuc3RyaW5naWZ5T2JqZWN0S2V5KHRoaXMuZXNjYXBlSFRNTChrZXkpKSArICc8c3Bhbj46IDwvc3Bhbj4nICsgdGhpcy5pbnNwZWN0KGRpZmZJdGVtLnZhbHVlKSk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdyZW1vdmVkJzpcbiAgICAgICAgcHJvcGVydHkgPSAoJzxkZWwgY2xhc3M9XCJkaWZmXCI+JyArIHRoaXMuc3RyaW5naWZ5T2JqZWN0S2V5KHRoaXMuZXNjYXBlSFRNTChrZXkpKSArICc8c3Bhbj46IDwvc3Bhbj4nICsgdGhpcy5pbnNwZWN0KGRpZmZJdGVtLnZhbHVlKSArICc8L2RlbD4nKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2FkZGVkJzpcbiAgICAgICAgcHJvcGVydHkgPSAoJzxpbnMgY2xhc3M9XCJkaWZmXCI+JyArIHRoaXMuc3RyaW5naWZ5T2JqZWN0S2V5KHRoaXMuZXNjYXBlSFRNTChrZXkpKSArICc8c3Bhbj46IDwvc3Bhbj4nICsgdGhpcy5pbnNwZWN0KGRpZmZJdGVtLnZhbHVlKSArICc8L2lucz4nKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ3ByaW1pdGl2ZSBjaGFuZ2UnOlxuICAgICAgICB2YXIgcHJlZml4ID0gdGhpcy5zdHJpbmdpZnlPYmplY3RLZXkodGhpcy5lc2NhcGVIVE1MKGtleSkpICsgJzxzcGFuPjogPC9zcGFuPic7XG4gICAgICAgIHByb3BlcnR5ID0gKFxuICAgICAgICAgICc8ZGVsIGNsYXNzPVwiZGlmZiBkaWZmLWtleVwiPicgKyBwcmVmaXggKyB0aGlzLmluc3BlY3QoZGlmZkl0ZW0ucmVtb3ZlZCkgKyAnPC9kZWw+PHNwYW4+LDwvc3Bhbj5cXG4nICtcbiAgICAgICAgICAnPGlucyBjbGFzcz1cImRpZmYgZGlmZi1rZXlcIj4nICsgcHJlZml4ICsgdGhpcy5pbnNwZWN0KGRpZmZJdGVtLmFkZGVkKSArICc8L2lucz4nKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ29iamVjdCBjaGFuZ2UnOlxuICAgICAgICBwcm9wZXJ0eSA9IHNoYWxsb3cgPyAnJyA6ICh0aGlzLnN0cmluZ2lmeU9iamVjdEtleShrZXkpICsgJzxzcGFuPjogPC9zcGFuPicgKyAoZGlmZk9ubHkgPyB0aGlzLmZvcm1hdENoYW5nZXNUb1hNTFN0cmluZyhkaWZmSXRlbSkgOiB0aGlzLmZvcm1hdFRvSnNvblhNTFN0cmluZyhkaWZmSXRlbSkpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgcmV0dXJuIHByb3BlcnR5O1xuICB9XG5cblxuICAvKipcbiAgICogQHBhcmFtIG9ialxuICAgKiBAcmV0dXJuXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqL1xuICBwcml2YXRlIGluc3BlY3Qob2JqLCBzaGFsbG93PzogYm9vbGVhbikge1xuICAgIHJldHVybiB0aGlzLl9pbnNwZWN0KCcnLCBvYmosIHNoYWxsb3cpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBhY2N1bXVsYXRvclxuICAgKiBAcGFyYW0gb2JqXG4gICAqIEBzZWUgaHR0cDovL2pzcGVyZi5jb20vY29udGludWF0aW9uLXBhc3Npbmctc3R5bGUvM1xuICAgKiBAcmV0dXJuXG4gICAqIEBwYXJhbSBzaGFsbG93XG4gICAqL1xuICBwcml2YXRlIF9pbnNwZWN0KGFjY3VtdWxhdG9yOiBzdHJpbmcsIG9iajogT2JqZWN0LCBzaGFsbG93Pykge1xuICAgIHN3aXRjaCAodHlwZW9mIG9iaikge1xuICAgICAgY2FzZSAnb2JqZWN0JzpcbiAgICAgICAgaWYgKCFvYmopIHtcbiAgICAgICAgICBhY2N1bXVsYXRvciArPSAnbnVsbCc7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNoYWxsb3cpIHtcbiAgICAgICAgICBhY2N1bXVsYXRvciArPSAnW29iamVjdF0nO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGxldCBrZXlzID0gT2JqZWN0LmtleXMob2JqKTtcbiAgICAgICAgbGV0IGxlbmd0aCA9IGtleXMubGVuZ3RoO1xuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgYWNjdW11bGF0b3IgKz0gJzxzcGFuPicgKyB0aGlzLm9wZW5DaGFyICsgdGhpcy5jbG9zZUNoYXIgKyAnPC9zcGFuPic7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWNjdW11bGF0b3IgKz0gJzxzcGFuPicgKyB0aGlzLm9wZW5DaGFyICsgJzwvc3Bhbj5cXG48ZGl2IGNsYXNzPVwiZGlmZi1sZXZlbFwiPic7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IGtleSA9IGtleXNbaV07XG4gICAgICAgICAgICBhY2N1bXVsYXRvciA9IHRoaXMuX2luc3BlY3QoYWNjdW11bGF0b3IgKyB0aGlzLnN0cmluZ2lmeU9iamVjdEtleSh0aGlzLmVzY2FwZUhUTUwoa2V5KSkgKyAnPHNwYW4+OiA8L3NwYW4+Jywgb2JqW2tleV0pO1xuICAgICAgICAgICAgaWYgKGkgPCBsZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgIGFjY3VtdWxhdG9yICs9ICc8c3Bhbj4sPC9zcGFuPlxcbic7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGFjY3VtdWxhdG9yICs9ICdcXG48L2Rpdj48c3Bhbj4nICsgdGhpcy5jbG9zZUNoYXIgKyAnPC9zcGFuPidcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgYWNjdW11bGF0b3IgKz0gSlNPTi5zdHJpbmdpZnkodGhpcy5lc2NhcGVIVE1MKG9iaikpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAndW5kZWZpbmVkJzpcbiAgICAgICAgYWNjdW11bGF0b3IgKz0gJ3VuZGVmaW5lZCc7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBhY2N1bXVsYXRvciArPSB0aGlzLmVzY2FwZUhUTUwoU3RyaW5nKG9iaikpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gICAgcmV0dXJuIGFjY3VtdWxhdG9yO1xuICB9XG5cblxuICAvKipcbiAgICogQHBhcmFtIGtleVxuICAgKiBAcmV0dXJuXG4gICAqL1xuICBwcml2YXRlIHN0cmluZ2lmeU9iamVjdEtleShrZXkpIDogc3RyaW5ne1xuICAgIHJldHVybiAvXlthLXowLTlfJF0qJC9pLnRlc3Qoa2V5KSA/XG4gICAgICBrZXkgOlxuICAgICAgSlNPTi5zdHJpbmdpZnkoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gc3RyaW5nXG4gICAqIEByZXR1cm5cbiAgICovXG4gIHByaXZhdGUgZXNjYXBlSFRNTChzdHJpbmcpIHtcbiAgICByZXR1cm4gc3RyaW5nLnJlcGxhY2UoLyYvZywgJyZhbXA7JykucmVwbGFjZSgvPC9nLCAnJmx0OycpLnJlcGxhY2UoLz4vZywgJyZndDsnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gb2JqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBwcml2YXRlIGVxdWFsT2JqKG9iaikge1xuICAgIHJldHVybiB7XG4gICAgICBjaGFuZ2VkOiAnZXF1YWwnLFxuICAgICAgdmFsdWU6IG9ialxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gYVxuICAgKiBAcGFyYW0gYlxuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgcHJpdmF0ZSBpc1ZhbGlkQXR0cihhOiBPYmplY3QsIGI6IE9iamVjdCk6IGJvb2xlYW4ge1xuICAgIGxldCB0eXBlQSA9IHR5cGVvZiBhO1xuICAgIGxldCB0eXBlQiA9IHR5cGVvZiBiO1xuICAgIHJldHVybiAoYSAmJiBiICYmICh0eXBlQSA9PSAnb2JqZWN0JyB8fCB0eXBlQSA9PSAnZnVuY3Rpb24nKSAmJiAodHlwZUIgPT0gJ29iamVjdCcgfHwgdHlwZUIgPT0gJ2Z1bmN0aW9uJykpO1xuICB9XG59XG4iXX0=