ngx-markdown
Version:
Angular library that uses marked to parse markdown to html combined with Prism.js for synthax highlights
397 lines (385 loc) • 33.6 kB
JavaScript
import { Pipe, Inject, Injectable, Optional, PLATFORM_ID, SecurityContext, Component, ElementRef, EventEmitter, Input, Output, NgZone, NgModule } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
import { parse, Renderer } from 'marked';
import { map, first } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class LanguagePipe {
/**
* @param {?} value
* @param {?} language
* @return {?}
*/
transform(value, language) {
if (typeof value !== 'string') {
console.error(`LanguagePipe has been invoked with an invalid value type [${value}]`);
return value;
}
if (typeof language !== 'string') {
console.error(`LanguagePipe has been invoked with an invalid parameter [${language}]`);
return value;
}
return '```' + language + '\n' + value + '\n```';
}
}
LanguagePipe.decorators = [
{ type: Pipe, args: [{
name: 'language',
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MarkedOptions {
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @type {?} */
const errorSrcWithoutHttpClient = '[ngx-markdown] When using the [src] attribute you *have to* pass the `HttpClient` as a parameter of the `forRoot` method. See README for more information';
class MarkdownService {
/**
* @param {?} platform
* @param {?} http
* @param {?} domSanitizer
* @param {?} options
*/
constructor(platform, http, domSanitizer, options) {
this.platform = platform;
this.http = http;
this.domSanitizer = domSanitizer;
this.options = options;
if (!this.renderer) {
this.renderer = new Renderer();
}
}
/**
* @return {?}
*/
get renderer() { return this.options.renderer; }
/**
* @param {?} value
* @return {?}
*/
set renderer(value) {
this.options.renderer = value;
}
/**
* @param {?} markdown
* @param {?=} decodeHtml
* @param {?=} markedOptions
* @return {?}
*/
compile(markdown, decodeHtml = false, markedOptions = this.options) {
/** @type {?} */
const precompiled = this.precompile(markdown);
/** @type {?} */
const compiled = parse(decodeHtml ? this.decodeHtml(precompiled) : precompiled, markedOptions);
return markedOptions.sanitize && !markedOptions.sanitizer
? this.domSanitizer.sanitize(SecurityContext.HTML, compiled)
: compiled;
}
/**
* @param {?} src
* @return {?}
*/
getSource(src) {
if (!this.http) {
throw new Error(errorSrcWithoutHttpClient);
}
return this.http
.get(src, { responseType: 'text' })
.pipe(map(markdown => this.handleExtension(src, markdown)));
}
/**
* @return {?}
*/
highlight() {
if (isPlatformBrowser(this.platform) && typeof Prism !== 'undefined') {
Prism.highlightAll(false);
}
}
/**
* @param {?} html
* @return {?}
*/
decodeHtml(html) {
if (isPlatformBrowser(this.platform)) {
/** @type {?} */
const textarea = document.createElement('textarea');
textarea.innerHTML = html;
return textarea.value;
}
return html;
}
/**
* @param {?} src
* @param {?} markdown
* @return {?}
*/
handleExtension(src, markdown) {
/** @type {?} */
const extension = src
? src.split('.').splice(-1).join()
: null;
return extension !== 'md'
? '```' + extension + '\n' + markdown + '\n```'
: markdown;
}
/**
* @param {?} markdown
* @return {?}
*/
precompile(markdown) {
if (!markdown) {
return '';
}
/** @type {?} */
let indentStart;
return markdown
.split('\n')
.map(line => {
/** @type {?} */
let lineIdentStart = indentStart;
// find position of 1st non-whitespace character
// to determine the current line indentation start
if (line.length > 0) {
lineIdentStart = isNaN(lineIdentStart)
? line.search(/\S|$/)
: Math.min(line.search(/\S|$/), lineIdentStart);
}
// keep 1st non-whitespace line indentation
// as base reference for other lines
if (isNaN(indentStart)) {
indentStart = lineIdentStart;
}
// remove whitespaces before current line indentation
return !!lineIdentStart
? line.substring(lineIdentStart)
: line;
}).join('\n');
}
}
MarkdownService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
MarkdownService.ctorParameters = () => [
{ type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
{ type: HttpClient, decorators: [{ type: Optional }] },
{ type: DomSanitizer },
{ type: MarkedOptions }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MarkdownComponent {
/**
* @param {?} element
* @param {?} markdownService
*/
constructor(element, markdownService) {
this.element = element;
this.markdownService = markdownService;
this.error = new EventEmitter();
this.load = new EventEmitter();
}
/**
* @return {?}
*/
get _isTranscluded() {
return !this._data && !this._src;
}
/**
* @return {?}
*/
get data() { return this._data; }
/**
* @param {?} value
* @return {?}
*/
set data(value) {
this._data = value;
this.render(value);
}
/**
* @return {?}
*/
get src() { return this._src; }
/**
* @param {?} value
* @return {?}
*/
set src(value) {
this._src = value;
this.markdownService
.getSource(value)
.subscribe(markdown => {
this.render(markdown);
this.load.emit(markdown);
}, error => this.error.emit(error));
}
/**
* @return {?}
*/
ngAfterViewInit() {
if (this._isTranscluded) {
this.render(this.element.nativeElement.innerHTML, true);
}
}
/**
* @param {?} markdown
* @param {?=} decodeHtml
* @return {?}
*/
render(markdown, decodeHtml = false) {
this.element.nativeElement.innerHTML = this.markdownService.compile(markdown, decodeHtml);
this.markdownService.highlight();
}
}
MarkdownComponent.decorators = [
{ type: Component, args: [{
// tslint:disable-next-line:component-selector
selector: 'markdown, [markdown]',
template: '<ng-content></ng-content>',
},] },
];
/** @nocollapse */
MarkdownComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: MarkdownService }
];
MarkdownComponent.propDecorators = {
data: [{ type: Input }],
src: [{ type: Input }],
error: [{ type: Output }],
load: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MarkdownPipe {
/**
* @param {?} markdownService
* @param {?} zone
*/
constructor(markdownService, zone) {
this.markdownService = markdownService;
this.zone = zone;
}
/**
* @param {?} value
* @return {?}
*/
transform(value) {
if (typeof value !== 'string') {
console.error(`MarkdownPipe has been invoked with an invalid value type [${value}]`);
return value;
}
/** @type {?} */
const markdown = this.markdownService.compile(value);
this.zone.onStable
.pipe(first())
.subscribe(() => this.markdownService.highlight());
return markdown;
}
}
MarkdownPipe.decorators = [
{ type: Pipe, args: [{
name: 'markdown',
},] },
];
/** @nocollapse */
MarkdownPipe.ctorParameters = () => [
{ type: MarkdownService },
{ type: NgZone }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @type {?} */
const initialMarkedOptions = {
provide: MarkedOptions,
useValue: {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false,
},
};
/** @type {?} */
const sharedDeclarations = [
LanguagePipe,
MarkdownComponent,
MarkdownPipe,
];
class MarkdownModule {
/**
* @param {?=} markdownModuleConfig
* @return {?}
*/
static forRoot(markdownModuleConfig) {
return {
ngModule: MarkdownModule,
providers: [
MarkdownService,
...(markdownModuleConfig
? [
markdownModuleConfig.loader || [],
markdownModuleConfig.markedOptions || initialMarkedOptions,
]
: [initialMarkedOptions]),
],
};
}
/**
* @return {?}
*/
static forChild() {
return {
ngModule: MarkdownModule,
};
}
}
MarkdownModule.decorators = [
{ type: NgModule, args: [{
exports: [
...sharedDeclarations,
],
declarations: [
...sharedDeclarations,
],
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MarkedRenderer extends Renderer {
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
export { LanguagePipe, MarkdownComponent, initialMarkedOptions, MarkdownModule, MarkdownPipe, errorSrcWithoutHttpClient, MarkdownService, MarkedOptions, MarkedRenderer };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hcmtkb3duLmpzLm1hcCIsInNvdXJjZXMiOlsibmc6Ly9uZ3gtbWFya2Rvd24vc3JjL2xhbmd1YWdlLnBpcGUudHMiLCJuZzovL25neC1tYXJrZG93bi9zcmMvbWFya2VkLW9wdGlvbnMudHMiLCJuZzovL25neC1tYXJrZG93bi9zcmMvbWFya2Rvd24uc2VydmljZS50cyIsIm5nOi8vbmd4LW1hcmtkb3duL3NyYy9tYXJrZG93bi5jb21wb25lbnQudHMiLCJuZzovL25neC1tYXJrZG93bi9zcmMvbWFya2Rvd24ucGlwZS50cyIsIm5nOi8vbmd4LW1hcmtkb3duL3NyYy9tYXJrZG93bi5tb2R1bGUudHMiLCJuZzovL25neC1tYXJrZG93bi9zcmMvbWFya2VkLXJlbmRlcmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFBpcGUsIFBpcGVUcmFuc2Zvcm0gfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbkBQaXBlKHtcclxuICBuYW1lOiAnbGFuZ3VhZ2UnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTGFuZ3VhZ2VQaXBlIGltcGxlbWVudHMgUGlwZVRyYW5zZm9ybSB7XHJcblxyXG4gIHRyYW5zZm9ybSh2YWx1ZTogc3RyaW5nLCBsYW5ndWFnZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYExhbmd1YWdlUGlwZSBoYXMgYmVlbiBpbnZva2VkIHdpdGggYW4gaW52YWxpZCB2YWx1ZSB0eXBlIFske3ZhbHVlfV1gKTtcclxuICAgICAgcmV0dXJuIHZhbHVlO1xyXG4gICAgfVxyXG4gICAgaWYgKHR5cGVvZiBsYW5ndWFnZSAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgY29uc29sZS5lcnJvcihgTGFuZ3VhZ2VQaXBlIGhhcyBiZWVuIGludm9rZWQgd2l0aCBhbiBpbnZhbGlkIHBhcmFtZXRlciBbJHtsYW5ndWFnZX1dYCk7XHJcbiAgICAgIHJldHVybiB2YWx1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiAnYGBgJyArIGxhbmd1YWdlICsgJ1xcbicgKyAgdmFsdWUgKyAnXFxuYGBgJztcclxuICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgUmVuZGVyZXIgfSBmcm9tICdtYXJrZWQnO1xyXG5cclxuZXhwb3J0IGNsYXNzIE1hcmtlZE9wdGlvbnMgaW1wbGVtZW50cyBtYXJrZWQuTWFya2VkT3B0aW9ucyB7XHJcbiAgLyoqXHJcbiAgICogQSBwcmVmaXggVVJMIGZvciBhbnkgcmVsYXRpdmUgbGluay5cclxuICAgKi9cclxuICBiYXNlVXJsPzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBFbmFibGUgR0ZNIGxpbmUgYnJlYWtzLiBUaGlzIG9wdGlvbiByZXF1aXJlcyB0aGUgZ2ZtIG9wdGlvbiB0byBiZSB0cnVlLlxyXG4gICAqL1xyXG4gIGJyZWFrcz86IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIEVuYWJsZSBHaXRIdWIgZmxhdm9yZWQgbWFya2Rvd24uXHJcbiAgICovXHJcbiAgZ2ZtPzogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogSW5jbHVkZSBhbiBpZCBhdHRyaWJ1dGUgd2hlbiBlbWl0dGluZyBoZWFkaW5ncy5cclxuICAgKi9cclxuICBoZWFkZXJJZHM/OiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBTZXQgdGhlIHByZWZpeCBmb3IgaGVhZGVyIHRhZyBpZHMuXHJcbiAgICovXHJcbiAgaGVhZGVyUHJlZml4Pzogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBTZXQgdGhlIHByZWZpeCBmb3IgY29kZSBibG9jayBjbGFzc2VzLlxyXG4gICAqL1xyXG4gIGxhbmdQcmVmaXg/OiBzdHJpbmc7XHJcblxyXG4gIC8qKlxyXG4gICAqIE1hbmdsZSBhdXRvbGlua3MgKDxlbWFpbEBkb21haW4uY29tPikuXHJcbiAgICovXHJcbiAgbWFuZ2xlPzogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogQ29uZm9ybSB0byBvYnNjdXJlIHBhcnRzIG9mIG1hcmtkb3duLnBsIGFzIG11Y2ggYXMgcG9zc2libGUuIERvbid0IGZpeCBhbnkgb2YgdGhlIG9yaWdpbmFsIG1hcmtkb3duIGJ1Z3Mgb3IgcG9vciBiZWhhdmlvci5cclxuICAgKi9cclxuICBwZWRhbnRpYz86IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIFR5cGU6IG9iamVjdCBEZWZhdWx0OiBuZXcgUmVuZGVyZXIoKVxyXG4gICAqXHJcbiAgICogQW4gb2JqZWN0IGNvbnRhaW5pbmcgZnVuY3Rpb25zIHRvIHJlbmRlciB0b2tlbnMgdG8gSFRNTC5cclxuICAgKi9cclxuICByZW5kZXJlcj86IFJlbmRlcmVyO1xyXG5cclxuICAvKipcclxuICAgKiBTYW5pdGl6ZSB0aGUgb3V0cHV0LiBJZ25vcmUgYW55IEhUTUwgdGhhdCBoYXMgYmVlbiBpbnB1dC5cclxuICAgKi9cclxuICBzYW5pdGl6ZT86IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIFNob3dzIGFuIEhUTUwgZXJyb3IgbWVzc2FnZSB3aGVuIHJlbmRlcmluZyBmYWlscy5cclxuICAgKi9cclxuICBzaWxlbnQ/OiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBVc2Ugc21hcnRlciBsaXN0IGJlaGF2aW9yIHRoYW4gdGhlIG9yaWdpbmFsIG1hcmtkb3duLiBNYXkgZXZlbnR1YWxseSBiZSBkZWZhdWx0IHdpdGggdGhlIG9sZCBiZWhhdmlvciBtb3ZlZCBpbnRvIHBlZGFudGljLlxyXG4gICAqL1xyXG4gIHNtYXJ0TGlzdHM/OiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBVc2UgXCJzbWFydFwiIHR5cG9ncmFoaWMgcHVuY3R1YXRpb24gZm9yIHRoaW5ncyBsaWtlIHF1b3RlcyBhbmQgZGFzaGVzLlxyXG4gICAqL1xyXG4gIHNtYXJ0eXBhbnRzPzogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogRW5hYmxlIEdGTSB0YWJsZXMuIFRoaXMgb3B0aW9uIHJlcXVpcmVzIHRoZSBnZm0gb3B0aW9uIHRvIGJlIHRydWUuXHJcbiAgICovXHJcbiAgdGFibGVzPzogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogR2VuZXJhdGUgY2xvc2luZyBzbGFzaCBmb3Igc2VsZi1jbG9zaW5nIHRhZ3MgKDxici8+IGluc3RlYWQgb2YgPGJyPilcclxuICAgKi9cclxuICB4aHRtbD86IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgZnVuY3Rpb24gdG8gaGlnaGxpZ2h0IGNvZGUgYmxvY2tzLiBUaGUgZnVuY3Rpb24gdGFrZXMgdGhyZWUgYXJndW1lbnRzOiBjb2RlLCBsYW5nLCBhbmQgY2FsbGJhY2suXHJcbiAgICovXHJcbiAgaGlnaGxpZ2h0Pyhjb2RlOiBzdHJpbmcsIGxhbmc6IHN0cmluZywgY2FsbGJhY2s/OiAoZXJyb3I6IGFueSB8IHVuZGVmaW5lZCwgY29kZTogc3RyaW5nKSA9PiB2b2lkKTogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBPcHRpb25hbGx5IHNhbml0aXplIGZvdW5kIEhUTUwgd2l0aCBhIHNhbml0aXplciBmdW5jdGlvbi5cclxuICAgKi9cclxuICBzYW5pdGl6ZXI/KGh0bWw6IHN0cmluZyk6IHN0cmluZztcclxufVxyXG4iLCJpbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XHJcbmltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgT3B0aW9uYWwsIFBMQVRGT1JNX0lELCBTZWN1cml0eUNvbnRleHQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRG9tU2FuaXRpemVyIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XHJcbmltcG9ydCB7IHBhcnNlLCBSZW5kZXJlciB9IGZyb20gJ21hcmtlZCc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5cclxuaW1wb3J0IHsgTWFya2VkT3B0aW9ucyB9IGZyb20gJy4vbWFya2VkLW9wdGlvbnMnO1xyXG5cclxuZGVjbGFyZSB2YXIgUHJpc206IHtcclxuICBoaWdobGlnaHRBbGw6IChhc3luYzogYm9vbGVhbikgPT4gdm9pZDtcclxufTtcclxuXHJcbi8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTptYXgtbGluZS1sZW5ndGhcclxuZXhwb3J0IGNvbnN0IGVycm9yU3JjV2l0aG91dEh0dHBDbGllbnQgPSAnW25neC1tYXJrZG93bl0gV2hlbiB1c2luZyB0aGUgW3NyY10gYXR0cmlidXRlIHlvdSAqaGF2ZSB0byogcGFzcyB0aGUgYEh0dHBDbGllbnRgIGFzIGEgcGFyYW1ldGVyIG9mIHRoZSBgZm9yUm9vdGAgbWV0aG9kLiBTZWUgUkVBRE1FIGZvciBtb3JlIGluZm9ybWF0aW9uJztcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIE1hcmtkb3duU2VydmljZSB7XHJcbiAgZ2V0IHJlbmRlcmVyKCk6IFJlbmRlcmVyIHsgcmV0dXJuIHRoaXMub3B0aW9ucy5yZW5kZXJlcjsgfVxyXG4gIHNldCByZW5kZXJlcih2YWx1ZTogbWFya2VkLlJlbmRlcmVyKSB7XHJcbiAgICB0aGlzLm9wdGlvbnMucmVuZGVyZXIgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybTogT2JqZWN0LFxyXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxyXG4gICAgcHJpdmF0ZSBkb21TYW5pdGl6ZXI6IERvbVNhbml0aXplcixcclxuICAgIHB1YmxpYyBvcHRpb25zOiBNYXJrZWRPcHRpb25zLFxyXG4gICkge1xyXG4gICAgaWYgKCF0aGlzLnJlbmRlcmVyKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyZXIgPSBuZXcgUmVuZGVyZXIoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNvbXBpbGUobWFya2Rvd246IHN0cmluZywgZGVjb2RlSHRtbCA9IGZhbHNlLCBtYXJrZWRPcHRpb25zID0gdGhpcy5vcHRpb25zKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IHByZWNvbXBpbGVkID0gdGhpcy5wcmVjb21waWxlKG1hcmtkb3duKTtcclxuICAgIGNvbnN0IGNvbXBpbGVkID0gcGFyc2UoXHJcbiAgICAgIGRlY29kZUh0bWwgPyB0aGlzLmRlY29kZUh0bWwocHJlY29tcGlsZWQpIDogcHJlY29tcGlsZWQsXHJcbiAgICAgIG1hcmtlZE9wdGlvbnMpO1xyXG4gICAgcmV0dXJuIG1hcmtlZE9wdGlvbnMuc2FuaXRpemUgJiYgIW1hcmtlZE9wdGlvbnMuc2FuaXRpemVyXHJcbiAgICAgID8gdGhpcy5kb21TYW5pdGl6ZXIuc2FuaXRpemUoU2VjdXJpdHlDb250ZXh0LkhUTUwsIGNvbXBpbGVkKVxyXG4gICAgICA6IGNvbXBpbGVkO1xyXG4gIH1cclxuXHJcbiAgZ2V0U291cmNlKHNyYzogc3RyaW5nKTogT2JzZXJ2YWJsZTxzdHJpbmc+IHtcclxuICAgIGlmICghdGhpcy5odHRwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvclNyY1dpdGhvdXRIdHRwQ2xpZW50KTtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLmh0dHBcclxuICAgICAgLmdldChzcmMsIHsgcmVzcG9uc2VUeXBlOiAndGV4dCcgfSlcclxuICAgICAgLnBpcGUobWFwKG1hcmtkb3duID0+IHRoaXMuaGFuZGxlRXh0ZW5zaW9uKHNyYywgbWFya2Rvd24pKSk7XHJcbiAgfVxyXG5cclxuICBoaWdobGlnaHQoKSB7XHJcbiAgICBpZiAoaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybSkgJiYgdHlwZW9mIFByaXNtICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICBQcmlzbS5oaWdobGlnaHRBbGwoZmFsc2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBkZWNvZGVIdG1sKGh0bWw6IHN0cmluZykge1xyXG4gICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm0pKSB7XHJcbiAgICAgIGNvbnN0IHRleHRhcmVhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGV4dGFyZWEnKTtcclxuICAgICAgdGV4dGFyZWEuaW5uZXJIVE1MID0gaHRtbDtcclxuICAgICAgcmV0dXJuIHRleHRhcmVhLnZhbHVlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGh0bWw7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZUV4dGVuc2lvbihzcmM6IHN0cmluZywgbWFya2Rvd246IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBleHRlbnNpb24gPSBzcmNcclxuICAgICAgPyBzcmMuc3BsaXQoJy4nKS5zcGxpY2UoLTEpLmpvaW4oKVxyXG4gICAgICA6IG51bGw7XHJcbiAgICByZXR1cm4gZXh0ZW5zaW9uICE9PSAnbWQnXHJcbiAgICAgID8gJ2BgYCcgKyBleHRlbnNpb24gKyAnXFxuJyArIG1hcmtkb3duICsgJ1xcbmBgYCdcclxuICAgICAgOiBtYXJrZG93bjtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJlY29tcGlsZShtYXJrZG93bjogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGlmICghbWFya2Rvd24pIHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG4gICAgbGV0IGluZGVudFN0YXJ0OiBudW1iZXI7XHJcbiAgICByZXR1cm4gbWFya2Rvd25cclxuICAgICAgLnNwbGl0KCdcXG4nKVxyXG4gICAgICAubWFwKGxpbmUgPT4ge1xyXG4gICAgICAgIC8vIHNldCBjdXJyZW50IGxpbmUgaWRlbnQgc3RhcnQgdG8gYmFzZSByZWZlcmVuY2UgaW5kZW50YXRpb25cclxuICAgICAgICBsZXQgbGluZUlkZW50U3RhcnQgPSBpbmRlbnRTdGFydDtcclxuICAgICAgICAvLyBmaW5kIHBvc2l0aW9uIG9mIDFzdCBub24td2hpdGVzcGFjZSBjaGFyYWN0ZXJcclxuICAgICAgICAvLyB0byBkZXRlcm1pbmUgdGhlIGN1cnJlbnQgbGluZSBpbmRlbnRhdGlvbiBzdGFydFxyXG4gICAgICAgIGlmIChsaW5lLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgIGxpbmVJZGVudFN0YXJ0ID0gaXNOYU4obGluZUlkZW50U3RhcnQpXHJcbiAgICAgICAgICAgID8gbGluZS5zZWFyY2goL1xcU3wkLylcclxuICAgICAgICAgICAgOiBNYXRoLm1pbihsaW5lLnNlYXJjaCgvXFxTfCQvKSwgbGluZUlkZW50U3RhcnQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICAvLyBrZWVwIDFzdCBub24td2hpdGVzcGFjZSBsaW5lIGluZGVudGF0aW9uXHJcbiAgICAgICAgLy8gYXMgYmFzZSByZWZlcmVuY2UgZm9yIG90aGVyIGxpbmVzXHJcbiAgICAgICAgaWYgKGlzTmFOKGluZGVudFN0YXJ0KSkge1xyXG4gICAgICAgICAgaW5kZW50U3RhcnQgPSBsaW5lSWRlbnRTdGFydDtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gcmVtb3ZlIHdoaXRlc3BhY2VzIGJlZm9yZSBjdXJyZW50IGxpbmUgaW5kZW50YXRpb25cclxuICAgICAgICByZXR1cm4gISFsaW5lSWRlbnRTdGFydFxyXG4gICAgICAgICAgPyBsaW5lLnN1YnN0cmluZyhsaW5lSWRlbnRTdGFydClcclxuICAgICAgICAgIDogbGluZTtcclxuICAgICAgfSkuam9pbignXFxuJyk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcblxyXG5pbXBvcnQgeyBNYXJrZG93blNlcnZpY2UgfSBmcm9tICcuL21hcmtkb3duLnNlcnZpY2UnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOmNvbXBvbmVudC1zZWxlY3RvclxyXG4gIHNlbGVjdG9yOiAnbWFya2Rvd24sIFttYXJrZG93bl0nLFxyXG4gIHRlbXBsYXRlOiAnPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PicsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYXJrZG93bkNvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQge1xyXG4gIHByaXZhdGUgX2RhdGE6IHN0cmluZztcclxuICBwcml2YXRlIF9zcmM6IHN0cmluZztcclxuXHJcbiAgcHJpdmF0ZSBnZXQgX2lzVHJhbnNjbHVkZWQoKSB7XHJcbiAgICByZXR1cm4gIXRoaXMuX2RhdGEgJiYgIXRoaXMuX3NyYztcclxuICB9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IGRhdGEoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuX2RhdGE7IH1cclxuICBzZXQgZGF0YSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9kYXRhID0gdmFsdWU7XHJcbiAgICB0aGlzLnJlbmRlcih2YWx1ZSk7XHJcbiAgfVxyXG5cclxuICBASW5wdXQoKVxyXG4gIGdldCBzcmMoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuX3NyYzsgfVxyXG4gIHNldCBzcmModmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5fc3JjID0gdmFsdWU7XHJcbiAgICB0aGlzLm1hcmtkb3duU2VydmljZVxyXG4gICAgICAuZ2V0U291cmNlKHZhbHVlKVxyXG4gICAgICAuc3Vic2NyaWJlKFxyXG4gICAgICAgIG1hcmtkb3duID0+IHtcclxuICAgICAgICAgIHRoaXMucmVuZGVyKG1hcmtkb3duKTtcclxuICAgICAgICAgIHRoaXMubG9hZC5lbWl0KG1hcmtkb3duKTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGVycm9yID0+IHRoaXMuZXJyb3IuZW1pdChlcnJvciksXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICBAT3V0cHV0KCkgZXJyb3IgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuICBAT3V0cHV0KCkgbG9hZCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHB1YmxpYyBlbGVtZW50OiBFbGVtZW50UmVmLFxyXG4gICAgcHVibGljIG1hcmtkb3duU2VydmljZTogTWFya2Rvd25TZXJ2aWNlLFxyXG4gICkgeyB9XHJcblxyXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcclxuICAgIGlmICh0aGlzLl9pc1RyYW5zY2x1ZGVkKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyKHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LmlubmVySFRNTCwgdHJ1ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZW5kZXIobWFya2Rvd246IHN0cmluZywgZGVjb2RlSHRtbCA9IGZhbHNlKSB7XHJcbiAgICB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudC5pbm5lckhUTUwgPSB0aGlzLm1hcmtkb3duU2VydmljZS5jb21waWxlKG1hcmtkb3duLCBkZWNvZGVIdG1sKTtcclxuICAgIHRoaXMubWFya2Rvd25TZXJ2aWNlLmhpZ2hsaWdodCgpO1xyXG4gIH1cclxufVxyXG4iLCJpbXBvcnQgeyBOZ1pvbmUsIFBpcGUsIFBpcGVUcmFuc2Zvcm0gfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgZmlyc3QgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcblxyXG5pbXBvcnQgeyBNYXJrZG93blNlcnZpY2UgfSBmcm9tICcuL21hcmtkb3duLnNlcnZpY2UnO1xyXG5cclxuQFBpcGUoe1xyXG4gIG5hbWU6ICdtYXJrZG93bicsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYXJrZG93blBpcGUgaW1wbGVtZW50cyBQaXBlVHJhbnNmb3JtIHtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIG1hcmtkb3duU2VydmljZTogTWFya2Rvd25TZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSB6b25lOiBOZ1pvbmUsXHJcbiAgKSB7IH1cclxuXHJcbiAgdHJhbnNmb3JtKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgY29uc29sZS5lcnJvcihgTWFya2Rvd25QaXBlIGhhcyBiZWVuIGludm9rZWQgd2l0aCBhbiBpbnZhbGlkIHZhbHVlIHR5cGUgWyR7dmFsdWV9XWApO1xyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgbWFya2Rvd24gPSB0aGlzLm1hcmtkb3duU2VydmljZS5jb21waWxlKHZhbHVlKTtcclxuXHJcbiAgICB0aGlzLnpvbmUub25TdGFibGVcclxuICAgICAgLnBpcGUoZmlyc3QoKSlcclxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLm1hcmtkb3duU2VydmljZS5oaWdobGlnaHQoKSk7XHJcblxyXG4gICAgcmV0dXJuIG1hcmtkb3duO1xyXG4gIH1cclxufVxyXG4iLCJpbXBvcnQgeyBNb2R1bGVXaXRoUHJvdmlkZXJzLCBOZ01vZHVsZSwgUHJvdmlkZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbmltcG9ydCB7IExhbmd1YWdlUGlwZSB9IGZyb20gJy4vbGFuZ3VhZ2UucGlwZSc7XHJcbmltcG9ydCB7IE1hcmtkb3duQ29tcG9uZW50IH0gZnJvbSAnLi9tYXJrZG93bi5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBNYXJrZG93blBpcGUgfSBmcm9tICcuL21hcmtkb3duLnBpcGUnO1xyXG5pbXBvcnQgeyBNYXJrZG93blNlcnZpY2UgfSBmcm9tICcuL21hcmtkb3duLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBNYXJrZWRPcHRpb25zIH0gZnJvbSAnLi9tYXJrZWQtb3B0aW9ucyc7XHJcblxyXG4vLyBoYXZpbmcgYSBkZXBlbmRlbmN5IG9uIGBIdHRwQ2xpZW50TW9kdWxlYCB3aXRoaW4gYSBsaWJyYXJ5XHJcbi8vIGJyZWFrcyBhbGwgdGhlIGludGVyY2VwdG9ycyBmcm9tIHRoZSBhcHAgY29uc3VtaW5nIHRoZSBsaWJyYXJ5XHJcbi8vIGhlcmUsIHdlIGV4cGxpY2l0ZWx5IGFzayB0aGUgdXNlciB0byBwYXNzIGEgcHJvdmlkZXIgd2l0aFxyXG4vLyB0aGVpciBvd24gaW5zdGFuY2Ugb2YgYEh0dHBDbGllbnRNb2R1bGVgXHJcbmV4cG9ydCBpbnRlcmZhY2UgTWFya2Rvd25Nb2R1bGVDb25maWcge1xyXG4gIGxvYWRlcj86IFByb3ZpZGVyO1xyXG4gIG1hcmtlZE9wdGlvbnM/OiBQcm92aWRlcjtcclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IGluaXRpYWxNYXJrZWRPcHRpb25zOiBQcm92aWRlciA9IHtcclxuICBwcm92aWRlOiBNYXJrZWRPcHRpb25zLFxyXG4gIHVzZVZhbHVlOiB7XHJcbiAgICBnZm06IHRydWUsXHJcbiAgICB0YWJsZXM6IHRydWUsXHJcbiAgICBicmVha3M6IGZhbHNlLFxyXG4gICAgcGVkYW50aWM6IGZhbHNlLFxyXG4gICAgc2FuaXRpemU6IGZhbHNlLFxyXG4gICAgc21hcnRMaXN0czogdHJ1ZSxcclxuICAgIHNtYXJ0eXBhbnRzOiBmYWxzZSxcclxuICB9LFxyXG59O1xyXG5cclxuY29uc3Qgc2hhcmVkRGVjbGFyYXRpb25zID0gW1xyXG4gIExhbmd1YWdlUGlwZSxcclxuICBNYXJrZG93bkNvbXBvbmVudCxcclxuICBNYXJrZG93blBpcGUsXHJcbl07XHJcblxyXG5ATmdNb2R1bGUoe1xyXG4gIGV4cG9ydHM6IFtcclxuICAgIC4uLnNoYXJlZERlY2xhcmF0aW9ucyxcclxuICBdLFxyXG4gIGRlY2xhcmF0aW9uczogW1xyXG4gICAgLi4uc2hhcmVkRGVjbGFyYXRpb25zLFxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYXJrZG93bk1vZHVsZSB7XHJcbiAgc3RhdGljIGZvclJvb3QobWFya2Rvd25Nb2R1bGVDb25maWc/OiBNYXJrZG93bk1vZHVsZUNvbmZpZyk6IE1vZHVsZVdpdGhQcm92aWRlcnMge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbmdNb2R1bGU6IE1hcmtkb3duTW9kdWxlLFxyXG4gICAgICBwcm92aWRlcnM6IFtcclxuICAgICAgICBNYXJrZG93blNlcnZpY2UsXHJcbiAgICAgICAgLi4uKG1hcmtkb3duTW9kdWxlQ29uZmlnXHJcbiAgICAgICAgICA/IFtcclxuICAgICAgICAgICAgICBtYXJrZG93bk1vZHVsZUNvbmZpZy5sb2FkZXIgfHwgW10sXHJcbiAgICAgICAgICAgICAgbWFya2Rvd25Nb2R1bGVDb25maWcubWFya2VkT3B0aW9ucyB8fCBpbml0aWFsTWFya2VkT3B0aW9ucyxcclxuICAgICAgICAgICAgXVxyXG4gICAgICAgICAgOiBbaW5pdGlhbE1hcmtlZE9wdGlvbnNdKSxcclxuICAgICAgXSxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBzdGF0aWMgZm9yQ2hpbGQoKTogTW9kdWxlV2l0aFByb3ZpZGVycyB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBuZ01vZHVsZTogTWFya2Rvd25Nb2R1bGUsXHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG4iLCJpbXBvcnQgeyBSZW5kZXJlciB9IGZyb20gJ21hcmtlZCc7XHJcblxyXG5leHBvcnQgY2xhc3MgTWFya2VkUmVuZGVyZXIgZXh0ZW5kcyBSZW5kZXJlciB7IH1cclxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUEsTUFLYSxZQUFZOzs7Ozs7SUFFdkIsU0FBUyxDQUFDLEtBQWEsRUFBRSxRQUFnQjtRQUN2QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRTtZQUM3QixPQUFPLENBQUMsS0FBSyxDQUFDLDZEQUE2RCxLQUFLLEdBQUcsQ0FBQyxDQUFDO1lBQ3JGLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFDRCxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFBRTtZQUNoQyxPQUFPLENBQUMsS0FBSyxDQUFDLDREQUE0RCxRQUFRLEdBQUcsQ0FBQyxDQUFD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