@q149/angular-scrollspy
Version:
A simple lightweight library for Angular which automatically updates links to indicate the currently active section in the viewport
337 lines (328 loc) • 26.9 kB
JavaScript
import { Directive, Input, HostBinding, ChangeDetectorRef, Injectable, ContentChildren, Component, NgModule } from '@angular/core';
import { InViewportModule } from '@q149/angular-inviewport';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* A directive used to add an `active` class to a nav item
* when the section is in the viewport
*
* \@example
* ```html
* <a snScrollSpyItem for="foo" href="#section1">Section 1</a>
* ```
*
*/
class ScrollSpyItemDirective {
/**
* Creates an instance of ScrollSpyItemDirective.
* \@memberof ScrollSpyItemDirective
* @param {?} cdRef
*/
constructor(cdRef) {
this.cdRef = cdRef;
/**
* True if the nav item is the active item in the `items` list
* for `ScrollSpyDirective` instance
*
* \@memberof ScrollSpyItemDirective
*/
this.active = false;
/**
* If true means the section is in the viewport
*
* \@memberof ScrollSpyItemDirective
*/
this.inViewport = false;
}
/**
* Id of section that links navigates to
*
* \@readonly
* \@memberof ScrollSpyItemDirective
* @return {?}
*/
get section() {
return this.href.replace('#', '');
}
/**
* Manually trigger change detection
*
* \@memberof ScrollSpyItemDirective
* @return {?}
*/
detectChanges() {
this.cdRef.detectChanges();
}
}
ScrollSpyItemDirective.decorators = [
{ type: Directive, args: [{
selector: '[snScrollSpyItem]'
},] },
];
/** @nocollapse */
ScrollSpyItemDirective.ctorParameters = () => [
{ type: ChangeDetectorRef, },
];
ScrollSpyItemDirective.propDecorators = {
"active": [{ type: HostBinding, args: ['class.active',] },],
"for": [{ type: Input },],
"href": [{ type: Input },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* Service that stores a list of `Spy`'s and the state
* of their nav items `inViewport` and `active` state
*
*/
class ScrollSpyService {
constructor() {
/**
* List of `Spy`'s
*
* \@memberof ScrollSpyService
*/
this.spys = [];
/**
* Stores requests to add items to spy when spy hasn't been created
* yet. Once spy has been added then request will be made again.
*
* \@memberof ScrollSpyService
*/
this.buffer = [];
}
/**
* Add spy to list of `spys`
*
* \@memberof ScrollSpyService
* @param {?} id
* @param {?} items
* @return {?}
*/
addSpy(id, items) {
this.spys.push({ id, items });
const /** @type {?} */ buffer = this.buffer.filter(i => i.spyId === id);
this.buffer = this.buffer.filter(i => i.spyId !== id);
buffer.forEach(i => this.setSpySectionStatus(i.sectionId, i.spyId, i.inViewport));
}
/**
* Remove spy from list of `spys`
*
* \@memberof ScrollSpyService
* @param {?} id
* @return {?}
*/
removeSpy(id) {
const /** @type {?} */ i = this.spys.findIndex(s => s.id === id);
this.spys.splice(i, 1);
}
/**
* Set the `inViewport` status for a spy item then sets the active
* to true for the first item in the list that has `inViewport`
* set to true
*
* \@memberof ScrollSpyService
* @param {?} sectionId
* @param {?} spyId
* @param {?} inViewport
* @return {?}
*/
setSpySectionStatus(sectionId, spyId, inViewport) {
const /** @type {?} */ spy = this.spys.find(s => s.id === spyId);
if (!spy) {
this.buffer.push({ sectionId, spyId, inViewport });
return;
}
const /** @type {?} */ item = spy.items.find(i => i.section === sectionId);
if (!item) {
return;
}
item.inViewport = inViewport;
const /** @type {?} */ firstInViewport = spy.items.filter(i => i.inViewport)[0];
spy.items.forEach(i => (i.active = false));
if (firstInViewport) {
firstInViewport.active = true;
firstInViewport.detectChanges();
}
}
}
ScrollSpyService.decorators = [
{ type: Injectable },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* Adds `active` class to navigation links when section is in the viewport.
* Used in conjuction with `snScrollItem` directive which should be added
* to anchor links in the nav
*
* \@example
* ```
* <ul role="navigation" snScrollSpy id="foo">
* <li><a snScrollSpyItem for="foo" href="#section1">Section 1</a></li>
* <li><a snScrollSpyItem for="foo" href="#section2">Section 2</a></li>
* <li><a snScrollSpyItem for="foo" href="#section3">Section 3</a></li>
* <li><a snScrollSpyItem for="foo" href="#section4">Section 4</a></li>
* </ul>
* ```
*
*/
class ScrollSpyDirective {
/**
* Creates an instance of ScrollSpyDirective.
* \@memberof ScrollSpyDirective
* @param {?} scrollSpySvc
*/
constructor(scrollSpySvc) {
this.scrollSpySvc = scrollSpySvc;
}
/**
* Adds spy to list of spys in `ScrollSpyService`
*
* \@memberof ScrollSpyDirective
* @return {?}
*/
ngAfterViewInit() {
this.scrollSpySvc.addSpy(this.id, this.items);
}
/**
* Remove spy from list of spys when directive is destroyed
*
* \@memberof ScrollSpyDirective
* @return {?}
*/
ngOnDestroy() {
this.scrollSpySvc.removeSpy(this.id);
}
}
ScrollSpyDirective.decorators = [
{ type: Directive, args: [{
selector: '[snScrollSpy]'
},] },
];
/** @nocollapse */
ScrollSpyDirective.ctorParameters = () => [
{ type: ScrollSpyService, },
];
ScrollSpyDirective.propDecorators = {
"items": [{ type: ContentChildren, args: [ScrollSpyItemDirective,] },],
"id": [{ type: Input },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* A component to wrap section content within that will update the
* `ScrollSpyService` when it's in view
*
* \@example
* ```html
* <sn-scroll-spy-section id="section1" for="foo">
* ...
* </sn-scroll-spy-section>
* ```
*/
class ScrollSpySectionComponent {
/**
* Creates an instance of ScrollSpySectionComponent.
* \@memberof ScrollSpySectionComponent
* @param {?} scrollSpySvc
*/
constructor(scrollSpySvc) {
this.scrollSpySvc = scrollSpySvc;
/**
* Amount of time in ms to wait for other scroll events
* before running event handler
*
* \@default 0
* \@memberof ScrollSpySectionComponent
*/
this.debounce = 0;
}
/**
* Updates `ScrollSpy` section when element enters/leaves viewport
*
* \@memberof ScrollSpySectionComponent
* @param {?} inViewport
* @return {?}
*/
onInViewportChange(inViewport) {
this.scrollSpySvc.setSpySectionStatus(this.id, this.for, inViewport);
}
}
ScrollSpySectionComponent.decorators = [
{ type: Component, args: [{
selector: 'sn-scroll-spy-section',
template: `<div
class="sn-hidden"
snInViewport
[offsetTop]="500"
(inViewportChange)="onInViewportChange($event)"
[debounce]="debounce">
</div>
<ng-content></ng-content>
`,
styles: [`:host{display:block;position:relative}.sn-hidden{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;z-index:-1}`]
},] },
];
/** @nocollapse */
ScrollSpySectionComponent.ctorParameters = () => [
{ type: ScrollSpyService, },
];
ScrollSpySectionComponent.propDecorators = {
"id": [{ type: Input },],
"for": [{ type: Input },],
"debounce": [{ type: Input },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
const /** @type {?} */ directives = [ScrollSpyDirective, ScrollSpyItemDirective];
const /** @type {?} */ components = [ScrollSpySectionComponent];
const /** @type {?} */ providers = [ScrollSpyService];
/**
* A simple lightweight library for Angular which automatically
* updates links to indicate the currently active section in the viewport
*
*/
class ScrollSpyModule {
/**
* Specify a static method for root module to ensure providers are
* only provided once but allows the module to still be imported
* into other modules without reproviding services.
*
* \@memberof ScrollSpyModule
* @return {?}
*/
static forRoot() {
return {
ngModule: ScrollSpyModule,
providers: [...providers]
};
}
}
ScrollSpyModule.decorators = [
{ type: NgModule, args: [{
imports: [InViewportModule],
declarations: [...directives, ...components],
exports: [...directives, ...components]
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
export { ScrollSpyDirective, ScrollSpyItemDirective, ScrollSpySectionComponent, ScrollSpyService, ScrollSpyModule };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicTE0OS1hbmd1bGFyLXNjcm9sbHNweS5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vQHExNDkvYW5ndWxhci1zY3JvbGxzcHkvYXBwL3Njcm9sbC1zcHkvc2Nyb2xsLXNweS1pdGVtL3Njcm9sbC1zcHktaXRlbS5kaXJlY3RpdmUudHMiLCJuZzovL0BxMTQ5L2FuZ3VsYXItc2Nyb2xsc3B5L2FwcC9zY3JvbGwtc3B5L3Njcm9sbC1zcHktc2VydmljZS9zY3JvbGwtc3B5LnNlcnZpY2UudHMiLCJuZzovL0BxMTQ5L2FuZ3VsYXItc2Nyb2xsc3B5L2FwcC9zY3JvbGwtc3B5L3Njcm9sbC1zcHkvc2Nyb2xsLXNweS5kaXJlY3RpdmUudHMiLCJuZzovL0BxMTQ5L2FuZ3VsYXItc2Nyb2xsc3B5L2FwcC9zY3JvbGwtc3B5L3Njcm9sbC1zcHktc2VjdGlvbi9zY3JvbGwtc3B5LXNlY3Rpb24uY29tcG9uZW50LnRzIiwibmc6Ly9AcTE0OS9hbmd1bGFyLXNjcm9sbHNweS9hcHAvc2Nyb2xsLXNweS9zY3JvbGwtc3B5Lm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIERpcmVjdGl2ZSxcclxuICBJbnB1dCxcclxuICBIb3N0QmluZGluZyxcclxuICBDaGFuZ2VEZXRlY3RvclJlZlxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuLyoqXHJcbiAqIEEgZGlyZWN0aXZlIHVzZWQgdG8gYWRkIGFuIGBhY3RpdmVgIGNsYXNzIHRvIGEgbmF2IGl0ZW1cclxuICogd2hlbiB0aGUgc2VjdGlvbiBpcyBpbiB0aGUgdmlld3BvcnRcclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgaHRtbFxyXG4gKiA8YSBzblNjcm9sbFNweUl0ZW0gZm9yPVwiZm9vXCIgaHJlZj1cIiNzZWN0aW9uMVwiPlNlY3Rpb24gMTwvYT5cclxuICogYGBgXHJcbiAqXHJcbiAqL1xyXG5ARGlyZWN0aXZlKHtcclxuICBzZWxlY3RvcjogJ1tzblNjcm9sbFNweUl0ZW1dJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgU2Nyb2xsU3B5SXRlbURpcmVjdGl2ZSB7XHJcbiAgLyoqXHJcbiAgICogVHJ1ZSBpZiB0aGUgbmF2IGl0ZW0gaXMgdGhlIGFjdGl2ZSBpdGVtIGluIHRoZSBgaXRlbXNgIGxpc3RcclxuICAgKiBmb3IgYFNjcm9sbFNweURpcmVjdGl2ZWAgaW5zdGFuY2VcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlJdGVtRGlyZWN0aXZlXHJcbiAgICovXHJcbiAgQEhvc3RCaW5kaW5nKCdjbGFzcy5hY3RpdmUnKSBwdWJsaWMgYWN0aXZlID0gZmFsc2U7XHJcbiAgLyoqXHJcbiAgICogSUQgb2YgYFNjcm9sbFNweURpcmVjdGl2ZWAgaW5zdGFuY2VcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlJdGVtRGlyZWN0aXZlXHJcbiAgICovXHJcbiAgQElucHV0KCkgcHVibGljIGZvcjogc3RyaW5nO1xyXG4gIC8qKlxyXG4gICAqIEhhc2ggZm9yIHNlY3Rpb24gdG8gbGluayB0b1xyXG4gICAqXHJcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweUl0ZW1EaXJlY3RpdmVcclxuICAgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgaHJlZjogc3RyaW5nO1xyXG4gIC8qKlxyXG4gICAqIElmIHRydWUgbWVhbnMgdGhlIHNlY3Rpb24gaXMgaW4gdGhlIHZpZXdwb3J0XHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5SXRlbURpcmVjdGl2ZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBpblZpZXdwb3J0ID0gZmFsc2U7XHJcbiAgLyoqXHJcbiAgICogSWQgb2Ygc2VjdGlvbiB0aGF0IGxpbmtzIG5hdmlnYXRlcyB0b1xyXG4gICAqXHJcbiAgICogQHJlYWRvbmx5XHJcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweUl0ZW1EaXJlY3RpdmVcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0IHNlY3Rpb24oKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmhyZWYucmVwbGFjZSgnIycsICcnKTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBTY3JvbGxTcHlJdGVtRGlyZWN0aXZlLlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlJdGVtRGlyZWN0aXZlXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjZFJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYpIHt9XHJcbiAgLyoqXHJcbiAgICogTWFudWFsbHkgdHJpZ2dlciBjaGFuZ2UgZGV0ZWN0aW9uXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5SXRlbURpcmVjdGl2ZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBkZXRlY3RDaGFuZ2VzKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEluamVjdGFibGUsIFF1ZXJ5TGlzdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuaW1wb3J0IHsgU2Nyb2xsU3B5SXRlbURpcmVjdGl2ZSB9IGZyb20gJy4uL3Njcm9sbC1zcHktaXRlbS9zY3JvbGwtc3B5LWl0ZW0uZGlyZWN0aXZlJztcclxuaW1wb3J0IHsgU3B5IH0gZnJvbSAnLi4vc2hhcmVkL3NweS5tb2RlbCc7XHJcblxyXG4vKipcclxuICogU2VydmljZSB0aGF0IHN0b3JlcyBhIGxpc3Qgb2YgYFNweWAncyBhbmQgdGhlIHN0YXRlXHJcbiAqIG9mIHRoZWlyIG5hdiBpdGVtcyBgaW5WaWV3cG9ydGAgYW5kIGBhY3RpdmVgIHN0YXRlXHJcbiAqXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBTY3JvbGxTcHlTZXJ2aWNlIHtcclxuICAvKipcclxuICAgKiBMaXN0IG9mIGBTcHlgJ3NcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlTZXJ2aWNlXHJcbiAgICovXHJcbiAgcHVibGljIHNweXM6IFNweVtdID0gW107XHJcbiAgLyoqXHJcbiAgICogU3RvcmVzIHJlcXVlc3RzIHRvIGFkZCBpdGVtcyB0byBzcHkgd2hlbiBzcHkgaGFzbid0IGJlZW4gY3JlYXRlZFxyXG4gICAqIHlldC4gT25jZSBzcHkgaGFzIGJlZW4gYWRkZWQgdGhlbiByZXF1ZXN0IHdpbGwgYmUgbWFkZSBhZ2Fpbi5cclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlTZXJ2aWNlXHJcbiAgICovXHJcbiAgcHVibGljIGJ1ZmZlcjogYW55W10gPSBbXTtcclxuICAvKipcclxuICAgKiBBZGQgc3B5IHRvIGxpc3Qgb2YgYHNweXNgXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5U2VydmljZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBhZGRTcHkoaWQ6IHN0cmluZywgaXRlbXM6IFF1ZXJ5TGlzdDxTY3JvbGxTcHlJdGVtRGlyZWN0aXZlPik6IHZvaWQge1xyXG4gICAgdGhpcy5zcHlzLnB1c2goeyBpZCwgaXRlbXMgfSk7XHJcbiAgICBjb25zdCBidWZmZXIgPSB0aGlzLmJ1ZmZlci5maWx0ZXIoaSA9PiBpLnNweUlkID09PSBpZCk7XHJcbiAgICB0aGlzLmJ1ZmZlciA9IHRoaXMuYnVmZmVyLmZpbHRlcihpID0+IGkuc3B5SWQgIT09IGlkKTtcclxuICAgIGJ1ZmZlci5mb3JFYWNoKGkgPT5cclxuICAgICAgdGhpcy5zZXRTcHlTZWN0aW9uU3RhdHVzKGkuc2VjdGlvbklkLCBpLnNweUlkLCBpLmluVmlld3BvcnQpXHJcbiAgICApO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZW1vdmUgc3B5IGZyb20gbGlzdCBvZiBgc3B5c2BcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlTZXJ2aWNlXHJcbiAgICovXHJcbiAgcHVibGljIHJlbW92ZVNweShpZDogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBjb25zdCBpID0gdGhpcy5zcHlzLmZpbmRJbmRleChzID0+IHMuaWQgPT09IGlkKTtcclxuICAgIHRoaXMuc3B5cy5zcGxpY2UoaSwgMSk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIFNldCB0aGUgYGluVmlld3BvcnRgIHN0YXR1cyBmb3IgYSBzcHkgaXRlbSB0aGVuIHNldHMgdGhlIGFjdGl2ZVxyXG4gICAqIHRvIHRydWUgZm9yIHRoZSBmaXJzdCBpdGVtIGluIHRoZSBsaXN0IHRoYXQgaGFzIGBpblZpZXdwb3J0YFxyXG4gICAqIHNldCB0byB0cnVlXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5U2VydmljZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBzZXRTcHlTZWN0aW9uU3RhdHVzKFxyXG4gICAgc2VjdGlvbklkOiBzdHJpbmcsXHJcbiAgICBzcHlJZDogc3RyaW5nLFxyXG4gICAgaW5WaWV3cG9ydDogYm9vbGVhblxyXG4gICk6IHZvaWQge1xyXG4gICAgY29uc3Qgc3B5ID0gdGhpcy5zcHlzLmZpbmQocyA9PiBzLmlkID09PSBzcHlJZCk7XHJcbiAgICBpZiAoIXNweSkge1xyXG4gICAgICB0aGlzLmJ1ZmZlci5wdXNoKHsgc2VjdGlvbklkLCBzcHlJZCwgaW5WaWV3cG9ydCB9KTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgY29uc3QgaXRlbSA9IHNweS5pdGVtcy5maW5kKGkgPT4gaS5zZWN0aW9uID09PSBzZWN0aW9uSWQpO1xyXG4gICAgaWYgKCFpdGVtKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBpdGVtLmluVmlld3BvcnQgPSBpblZpZXdwb3J0O1xyXG4gICAgY29uc3QgZmlyc3RJblZpZXdwb3J0ID0gc3B5Lml0ZW1zLmZpbHRlcihpID0+IGkuaW5WaWV3cG9ydClbMF07XHJcbiAgICBzcHkuaXRlbXMuZm9yRWFjaChpID0+IChpLmFjdGl2ZSA9IGZhbHNlKSk7XHJcblxyXG4gICAgaWYgKGZpcnN0SW5WaWV3cG9ydCkge1xyXG4gICAgICBmaXJzdEluVmlld3BvcnQuYWN0aXZlID0gdHJ1ZTtcclxuICAgICAgZmlyc3RJblZpZXdwb3J0LmRldGVjdENoYW5nZXMoKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiaW1wb3J0IHtcclxuICBEaXJlY3RpdmUsXHJcbiAgQ29udGVudENoaWxkcmVuLFxyXG4gIFF1ZXJ5TGlzdCxcclxuICBBZnRlclZpZXdJbml0LFxyXG4gIElucHV0LFxyXG4gIE9uRGVzdHJveVxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuaW1wb3J0IHsgU2Nyb2xsU3B5SXRlbURpcmVjdGl2ZSB9IGZyb20gJy4uL3Njcm9sbC1zcHktaXRlbS9zY3JvbGwtc3B5LWl0ZW0uZGlyZWN0aXZlJztcclxuaW1wb3J0IHsgU2Nyb2xsU3B5U2VydmljZSB9IGZyb20gJy4uL3Njcm9sbC1zcHktc2VydmljZS9zY3JvbGwtc3B5LnNlcnZpY2UnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgYGFjdGl2ZWAgY2xhc3MgdG8gbmF2aWdhdGlvbiBsaW5rcyB3aGVuIHNlY3Rpb24gaXMgaW4gdGhlIHZpZXdwb3J0LlxyXG4gKiBVc2VkIGluIGNvbmp1Y3Rpb24gd2l0aCBgc25TY3JvbGxJdGVtYCBkaXJlY3RpdmUgd2hpY2ggc2hvdWxkIGJlIGFkZGVkXHJcbiAqIHRvIGFuY2hvciBsaW5rcyBpbiB0aGUgbmF2XHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYFxyXG4gKiA8dWwgcm9sZT1cIm5hdmlnYXRpb25cIiBzblNjcm9sbFNweSBpZD1cImZvb1wiPlxyXG4gKiAgPGxpPjxhIHNuU2Nyb2xsU3B5SXRlbSBmb3I9XCJmb29cIiBocmVmPVwiI3NlY3Rpb24xXCI+U2VjdGlvbiAxPC9hPjwvbGk+XHJcbiAqICA8bGk+PGEgc25TY3JvbGxTcHlJdGVtIGZvcj1cImZvb1wiIGhyZWY9XCIjc2VjdGlvbjJcIj5TZWN0aW9uIDI8L2E+PC9saT5cclxuICogIDxsaT48YSBzblNjcm9sbFNweUl0ZW0gZm9yPVwiZm9vXCIgaHJlZj1cIiNzZWN0aW9uM1wiPlNlY3Rpb24gMzwvYT48L2xpPlxyXG4gKiAgPGxpPjxhIHNuU2Nyb2xsU3B5SXRlbSBmb3I9XCJmb29cIiBocmVmPVwiI3NlY3Rpb240XCI+U2VjdGlvbiA0PC9hPjwvbGk+XHJcbiAqIDwvdWw+XHJcbiAqIGBgYFxyXG4gKlxyXG4gKi9cclxuQERpcmVjdGl2ZSh7XHJcbiAgc2VsZWN0b3I6ICdbc25TY3JvbGxTcHldJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgU2Nyb2xsU3B5RGlyZWN0aXZlIGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcclxuICAvKipcclxuICAgKiBDb2xsZWN0aW9uIG9mIGBTY3JvbGxTcHlJdGVtYC4gVGhleSBhcmUgdGhlIGxpc3Qgb2ZcclxuICAgKiBuYXYgaXRlbXMuXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5RGlyZWN0aXZlXHJcbiAgICovXHJcbiAgQENvbnRlbnRDaGlsZHJlbihTY3JvbGxTcHlJdGVtRGlyZWN0aXZlKVxyXG4gIHB1YmxpYyBpdGVtczogUXVlcnlMaXN0PFNjcm9sbFNweUl0ZW1EaXJlY3RpdmU+O1xyXG4gIC8qKlxyXG4gICAqIElEIG9mIHNjcm9sbFNweSBpbnN0YW5jZVxyXG4gICAqXHJcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweURpcmVjdGl2ZVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyBpZDogc3RyaW5nO1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgU2Nyb2xsU3B5RGlyZWN0aXZlLlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlEaXJlY3RpdmVcclxuICAgKi9cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNjcm9sbFNweVN2YzogU2Nyb2xsU3B5U2VydmljZSkge31cclxuICAvKipcclxuICAgKiBBZGRzIHNweSB0byBsaXN0IG9mIHNweXMgaW4gYFNjcm9sbFNweVNlcnZpY2VgXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5RGlyZWN0aXZlXHJcbiAgICovXHJcbiAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2Nyb2xsU3B5U3ZjLmFkZFNweSh0aGlzLmlkLCB0aGlzLml0ZW1zKTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogUmVtb3ZlIHNweSBmcm9tIGxpc3Qgb2Ygc3B5cyB3aGVuIGRpcmVjdGl2ZSBpcyBkZXN0cm95ZWRcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlEaXJlY3RpdmVcclxuICAgKi9cclxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLnNjcm9sbFNweVN2Yy5yZW1vdmVTcHkodGhpcy5pZCk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgU2Nyb2xsU3B5U2VydmljZSB9IGZyb20gJy4uL3Njcm9sbC1zcHktc2VydmljZS9zY3JvbGwtc3B5LnNlcnZpY2UnO1xyXG5cclxuLyoqXHJcbiAqIEEgY29tcG9uZW50IHRvIHdyYXAgc2VjdGlvbiBjb250ZW50IHdpdGhpbiB0aGF0IHdpbGwgdXBkYXRlIHRoZVxyXG4gKiBgU2Nyb2xsU3B5U2VydmljZWAgd2hlbiBpdCdzIGluIHZpZXdcclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgaHRtbFxyXG4gKiAgPHNuLXNjcm9sbC1zcHktc2VjdGlvbiBpZD1cInNlY3Rpb24xXCIgZm9yPVwiZm9vXCI+XHJcbiAqICAgIC4uLlxyXG4gKiAgPC9zbi1zY3JvbGwtc3B5LXNlY3Rpb24+XHJcbiAqIGBgYFxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdzbi1zY3JvbGwtc3B5LXNlY3Rpb24nLFxyXG4gIHRlbXBsYXRlOiBgPGRpdlxuICBjbGFzcz1cInNuLWhpZGRlblwiXG4gIHNuSW5WaWV3cG9ydFxuICBbb2Zmc2V0VG9wXT1cIjUwMFwiXG4gIChpblZpZXdwb3J0Q2hhbmdlKT1cIm9uSW5WaWV3cG9ydENoYW5nZSgkZXZlbnQpXCJcbiAgW2RlYm91bmNlXT1cImRlYm91bmNlXCI+XG48L2Rpdj5cbjxuZy1jb250ZW50PjwvbmctY29udGVudD5cbmAsXHJcbiAgc3R5bGVzOiBbYDpob3N0e2Rpc3BsYXk6YmxvY2s7cG9zaXRpb246cmVsYXRpdmV9LnNuLWhpZGRlbntib3R0b206MDtsZWZ0OjA7b3BhY2l0eTowO3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7dG9wOjA7ei1pbmRleDotMX1gXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgU2Nyb2xsU3B5U2VjdGlvbkNvbXBvbmVudCB7XHJcbiAgLyoqXHJcbiAgICogSWRlbnRpZmllcyB0aGUgc2VjdGlvblxyXG4gICAqXHJcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweVNlY3Rpb25Db21wb25lbnRcclxuICAgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgaWQ6IHN0cmluZztcclxuICAvKipcclxuICAgKiBTcGVjaWZpZXMgd2hpY2ggYFNjcm9sbFNweWAgaW5zdGFuY2UgdG8gdXBkYXRlXHJcbiAgICpcclxuICAgKiBAbWVtYmVyb2YgU2Nyb2xsU3B5U2VjdGlvbkNvbXBvbmVudFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyBmb3I6IHN0cmluZztcclxuICAvKipcclxuICAgKiBBbW91bnQgb2YgdGltZSBpbiBtcyB0byB3YWl0IGZvciBvdGhlciBzY3JvbGwgZXZlbnRzXHJcbiAgICogYmVmb3JlIHJ1bm5pbmcgZXZlbnQgaGFuZGxlclxyXG4gICAqXHJcbiAgICogQGRlZmF1bHQgMFxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlTZWN0aW9uQ29tcG9uZW50XHJcbiAgICovXHJcbiAgQElucHV0KCkgcHVibGljIGRlYm91bmNlID0gMDtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFNjcm9sbFNweVNlY3Rpb25Db21wb25lbnQuXHJcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweVNlY3Rpb25Db21wb25lbnRcclxuICAgKi9cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNjcm9sbFNweVN2YzogU2Nyb2xsU3B5U2VydmljZSkge31cclxuICAvKipcclxuICAgKiBVcGRhdGVzIGBTY3JvbGxTcHlgIHNlY3Rpb24gd2hlbiBlbGVtZW50IGVudGVycy9sZWF2ZXMgdmlld3BvcnRcclxuICAgKlxyXG4gICAqIEBtZW1iZXJvZiBTY3JvbGxTcHlTZWN0aW9uQ29tcG9uZW50XHJcbiAgICovXHJcbiAgcHVibGljIG9uSW5WaWV3cG9ydENoYW5nZShpblZpZXdwb3J0OiBib29sZWFuKTogdm9pZCB7XHJcbiAgICB0aGlzLnNjcm9sbFNweVN2Yy5zZXRTcHlTZWN0aW9uU3RhdHVzKHRoaXMuaWQsIHRoaXMuZm9yLCBpblZpZXdwb3J0KTtcclxuICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgTmdNb2R1bGUsIE1vZHVsZVdpdGhQcm92aWRlcnMsIFByb3ZpZGVyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBJblZpZXdwb3J0TW9kdWxlIH0gZnJvbSAnQHExNDkvYW5ndWxhci1pbnZpZXdwb3J0JztcblxuaW1wb3J0IHsgU2Nyb2xsU3B5RGlyZWN0aXZlIH0gZnJvbSAnLi9zY3JvbGwtc3B5L3Njcm9sbC1zcHkuZGlyZWN0aXZlJztcbmltcG9ydCB7IFNjcm9sbFNweVNlY3Rpb25Db21wb25lbnQgfSBmcm9tICcuL3Njcm9sbC1zcHktc2VjdGlvbi9zY3JvbGwtc3B5LXNlY3Rpb24uY29tcG9uZW50JztcbmltcG9ydCB7IFNjcm9sbFNweUl0ZW1EaXJlY3RpdmUgfSBmcm9tICcuL3Njcm9sbC1zcHktaXRlbS9zY3JvbGwtc3B5LWl0ZW0uZGlyZWN0aXZlJztcbmltcG9ydCB7IFNjcm9sbFNweVNlcnZpY2UgfSBmcm9tICcuL3Njcm9sbC1zcHktc2VydmljZS9zY3JvbGwtc3B5LnNlcnZpY2UnO1xuXG5jb25zdCBkaXJlY3RpdmVzOiBhbnlbXSA9IFtTY3JvbGxTcHlEaXJlY3RpdmUsIFNjcm9sbFNweUl0ZW1EaXJlY3RpdmVdO1xuXG5jb25zdCBjb21wb25lbnRzOiBhbnlbXSA9IFtTY3JvbGxTcHlTZWN0aW9uQ29tcG9uZW50XTtcblxuY29uc3QgcHJvdmlkZXJzOiBQcm92aWRlcltdID0gW1Njcm9sbFNweVNlcnZpY2VdO1xuXG4vKipcbiAqIEEgc2ltcGxlIGxpZ2h0d2VpZ2h0IGxpYnJhcnkgZm9yIEFuZ3VsYXIgd2hpY2ggYXV0b21hdGljYWxseVxuICogdXBkYXRlcyBsaW5rcyB0byBpbmRpY2F0ZSB0aGUgY3VycmVudGx5IGFjdGl2ZSBzZWN0aW9uIGluIHRoZSB2aWV3cG9ydFxuICpcbiAqL1xuQE5nTW9kdWxlKHtcbiAgaW1wb3J0czogW0luVmlld3BvcnRNb2R1bGVdLFxuICBkZWNsYXJhdGlvbnM6IFsuLi5kaXJlY3RpdmVzLCAuLi5jb21wb25lbnRzXSxcbiAgZXhwb3J0czogWy4uLmRpcmVjdGl2ZXMsIC4uLmNvbXBvbmVudHNdXG59KVxuZXhwb3J0IGNsYXNzIFNjcm9sbFNweU1vZHVsZSB7XG4gIC8qKlxuICAgKiBTcGVjaWZ5IGEgc3RhdGljIG1ldGhvZCBmb3Igcm9vdCBtb2R1bGUgdG8gZW5zdXJlIHByb3ZpZGVycyBhcmVcbiAgICogb25seSBwcm92aWRlZCBvbmNlIGJ1dCBhbGxvd3MgdGhlIG1vZHVsZSB0byBzdGlsbCBiZSBpbXBvcnRlZFxuICAgKiBpbnRvIG90aGVyIG1vZHVsZXMgd2l0aG91dCByZXByb3ZpZGluZyBzZXJ2aWNlcy5cbiAgICpcbiAgICogQG1lbWJlcm9mIFNjcm9sbFNweU1vZHVsZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmb3JSb290KCk6IE1vZHVsZVdpdGhQcm92aWRlcnMge1xuICAgIHJldHVybiB7XG4gICAgICBuZ01vZHVsZTogU2Nyb2xsU3B5TW9kdWxlLFxuICAgICAgcHJvdmlkZXJzOiBbLi4ucHJvdmlkZXJzXVxuICAgIH07XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7Ozs7Ozs7Ozs7QUFvQkE7Ozs7OztJQXVDRSxZ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