UNPKG

ngx-firebase-cms

Version:

Angular Content Management System using Google Firebase (Authentication, Storage & Firestore)

351 lines 33.5 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Component, ElementRef, ViewChild, HostListener } from '@angular/core'; import { UnsubscriptionService } from '../../service/unsubscription.service'; import { FormBuilder, FormControl, Validators } from '@angular/forms'; import { AngularFireAuth } from '@angular/fire/auth'; import { NzMessageService, NzNotificationService } from 'ng-zorro-antd'; import { AngularFireStorage } from '@angular/fire/storage'; import { AuthService } from '../../service/auth.service'; import { HelperService } from '../../service/helper.service'; import * as firebase from 'firebase/app'; import { of } from 'rxjs'; import { AngularFirestore } from '@angular/fire/firestore'; export class ProfileComponent { /** * @param {?} unsubscription * @param {?} afAuth * @param {?} afs * @param {?} message * @param {?} storage * @param {?} auth * @param {?} fb * @param {?} notification * @param {?} helper */ constructor(unsubscription, afAuth, afs, message, storage, auth, fb, notification, helper) { this.unsubscription = unsubscription; this.afAuth = afAuth; this.afs = afs; this.message = message; this.storage = storage; this.auth = auth; this.fb = fb; this.notification = notification; this.helper = helper; this.titlebar = { title: "Profile", description: "Edit your profile", breadcrumbs: [ { title: "Profile", icon: 'team' } ] }; this.showChangePassword = false; this.isLoading = false; this.showDisplayName = false; this.profileURL = null; this.beforeUpload = (/** * @param {?} file * @return {?} */ (file) => { if (file['type'] != "image/jpeg") { this.message.error("File type should be JPEG"); return false; } else if (file['size'] / 1024 / 1024 > 1) { this.message.error("File size should be less than 1 Mb"); return false; } else { return true; } }); this.uploadProfilePic = (/** * @param {?} item * @return {?} */ (item) => { this.message.success(`File is uploading`); /** @type {?} */ let timestamp = new Date().valueOf(); /** @type {?} */ let filePath = `/profile/${timestamp}.jpeg`; /** @type {?} */ let file = item['file']; /** @type {?} */ const task = this.storage.upload(filePath, file) .then((/** * @param {?} res * @return {?} */ res => { return this.storage.ref(filePath).getDownloadURL().toPromise(); })) .then((/** * @param {?} res * @return {?} */ res => { return this.afs.collection("users").doc(this.auth.uid).update({ "profileURL": res, "uploadTime": firebase.firestore.FieldValue.serverTimestamp() }); })) .then((/** * @param {?} res * @return {?} */ res => { this.auth.log(`changed profile pic ${timestamp}.jpeg`); this.message.success("File Uploaded"); })).catch((/** * @param {?} err * @return {?} */ err => { this.message.error(err); })); return of().subscribe((/** * @param {?} event * @return {?} */ (event) => { if (event['percent'] != 100) { item.onProgress(event, item.file); } else { item.onSuccess(event['body'], item.file, event); } }), (/** * @param {?} err * @return {?} */ (err) => { item.onError(err, item.file); })); }); } /** * @return {?} */ ngOnInit() { this.sub = this.auth.user$.subscribe((/** * @param {?} res * @return {?} */ res => { this.profileURL = res.profileURL; }), (/** * @param {?} err * @return {?} */ err => { })); this.initForm(); } /** * @return {?} */ ngOnDestroy() { this.sub.unsubscribe(); } /** * @return {?} */ initForm() { this.passwordForm = this.fb.group({ "previousPassword": new FormControl({ value: "", disabled: false }, [Validators.required]), "newPassword": new FormControl({ value: "", disabled: false }, [Validators.required]), }); this.displayNameForm = this.fb.group({ "displayName": new FormControl({ "value": this.auth.displayName, disabled: false }, [Validators.required]) }); } /** * @return {?} */ changePassword() { if (typeof this.passwordForm.value["newPassword"] == "string") this.passwordForm.controls["newPassword"].setValue(this.passwordForm.value["newPassword"].trim()); if (this.passwordForm.valid && !this.isLoading) { this.isLoading = true; this.afAuth.auth.signInWithEmailAndPassword(this.auth.email, this.passwordForm.value['previousPassword']).then((/** * @param {?} res * @return {?} */ res => { /** @type {?} */ let user = this.afAuth.auth.currentUser; return user.updatePassword(this.passwordForm.value["newPassword"]); })) .then((/** * @param {?} res * @return {?} */ res => { this.auth.log(` updated the password`); this.message.success(`Change the password`); this.showChangePassword = !this.showChangePassword; })) .catch((/** * @param {?} err * @return {?} */ err => { this.message.error(err); })); } else { this.passwordForm.controls["newPassword"].markAsDirty(); } } /** * @return {?} */ changeDisplayName() { if (typeof this.displayNameForm.value["displayName"] == "string") this.displayNameForm.controls["displayName"].setValue(this.displayNameForm.value["displayName"].trim()); if (this.displayNameForm.valid && !this.isLoading) { this.isLoading = true; this.afs.collection("users").doc(this.auth.uid).update({ "displayName": this.displayNameForm.value["displayName"], "uploadTime": firebase.firestore.FieldValue.serverTimestamp() }).then((/** * @param {?} res * @return {?} */ res => { this.isLoading = false; this.showDisplayName = !this.showDisplayName; })); } else { this.displayNameForm.controls["displayName"].markAsDirty(); } } /** * @return {?} */ getProfilePic() { return (this.profileURL) ? { 'background-image': 'url(\'' + this.profileURL + '\')' } : {}; } /** * @param {?} e * @return {?} */ keyboardEvent(e) { if (this.showChangePassword && e.key == 'Escape') { this.notification.blank("ESC", "Escape modal"); this.showChangePassword = false; } if (this.showDisplayName && e.key == 'Escape') { this.notification.blank("ESC", "Escape modal"); this.showDisplayName = false; } if (this.showChangePassword) { if (e.ctrlKey && e.key == 'Enter') { this.notification.blank("⌃ ENTER", "Form Submission"); this.changePassword(); } } if (this.showDisplayName && e.ctrlKey && e.key == 'Enter') { this.notification.blank("⌃ ENTER", "Form Submission"); this.changeDisplayName(); } } } ProfileComponent.decorators = [ { type: Component, args: [{ selector: 'aq-profile', template: "<aq-title-bar [data]=\"titlebar\"></aq-title-bar>\n\n<div class=\"container\">\n <h3>{{ (auth.user$ | async)?.displayName }}</h3>\n <p>Email: {{ (auth.user$ | async)?.email }}</p>\n <p>Roles: {{ (auth.user$ | async)?.roles }}</p>\n <p>Created on: {{ (auth.user$ | async)?.createdTime.toDate() | date: 'medium' }}</p>\n <p>Last login: {{ auth.lastLogin | date: 'medium' }}</p>\n\n <button class=\"m-r-10\" nz-tooltip nzTitle=\"Change Password\" nz-button (click)=\"showChangePassword=true\">\n <i nz-icon type=\"security-scan\" theme=\"outline\"></i> Password\n </button>\n\n <button class=\"m-r-10\" nz-tooltip nzTitle=\"Change Display Name\" nz-button (click)=\"showDisplayName=true\">\n <i nz-icon type=\"font-colors\" theme=\"outline\"></i> Display Name\n </button>\n\n <nz-upload class=\"m-r-10\" [nzBeforeUpload]=\"beforeUpload\" [nzCustomRequest]=\"uploadProfilePic\"\n [nzShowUploadList]=\"false\">\n <button #uploadButton nz-tooltip nzTitle=\"Change Profile Image\" nz-button>\n <i nz-icon type=\"picture\" theme=\"outline\"></i> Profile Image\n </button>\n </nz-upload>\n</div>\n\n<nz-drawer nzWidth=\"100%\" [nzVisible]=\"showChangePassword\" nzTitle=\"Change Password\" (nzOnClose)=\"showChangePassword = !showChangePassword\">\n <form nz-form [formGroup]=\"passwordForm\" (ngSubmit)=\"changePassword()\">\n <nz-form-item>\n <nz-form-control>\n <label>Previous Password</label>\n <input type=\"password\" nz-input formControlName=\"previousPassword\" placeholder=\"Previous Password\"\n autocomplete=\"password\" autofocus>\n <nz-form-explain\n *ngIf=\"passwordForm.get('previousPassword').dirty && passwordForm.get('previousPassword').errors\">\n Please input\n your previous password!</nz-form-explain>\n </nz-form-control>\n </nz-form-item>\n <nz-form-item>\n <nz-form-control>\n <label>New Password</label>\n <input type=\"password\" nz-input formControlName=\"newPassword\" placeholder=\"New Password\" autocomplete=\"password\" autofocus>\n <nz-form-explain\n *ngIf=\"passwordForm.get('newPassword').dirty && passwordForm.get('newPassword').errors\">Please input\n your new\n password!</nz-form-explain>\n </nz-form-control>\n </nz-form-item>\n </form>\n <div class=\"footer\">\n <button type=\"button\" (click)=\"changePassword()\" class=\"ant-btn ant-btn-primary\">Submit </button>\n <button type=\"button\" (click)=\"showChangePassword = !showChangePassword\" class=\"ant-btn\">Cancel </button>\n </div>\n</nz-drawer>\n\n<nz-drawer nzWidth=\"100%\" [nzVisible]=\"showDisplayName\" nzTitle=\"Change Display Name\" (nzOnClose)=\"showDisplayName = !showDisplayName\">\n <form nz-form [formGroup]=\"displayNameForm\" (ngSubmit)=\"changeDisplayName()\">\n <nz-form-item>\n <nz-form-control>\n <label>Your Display Name</label>\n <input type=\"text\" nz-input formControlName=\"displayName\" placeholder=\"Please enter your display name\"\n autocomplete=\"displayName\" autofocus>\n <nz-form-explain\n *ngIf=\"displayNameForm.get('displayName').dirty && displayNameForm.get('displayName').errors\">Please\n input\n your Display Name!</nz-form-explain>\n </nz-form-control>\n </nz-form-item>\n </form>\n <div class=\"footer\">\n <button type=\"button\" (click)=\"changeDisplayName()\" class=\"ant-btn ant-btn-primary\">Submit </button>\n <button type=\"button\" (click)=\"showDisplayName = !showDisplayName\" class=\"ant-btn\">Cancel </button>\n </div>\n</nz-drawer>\n", styles: [".img-rounded{border-radius:50%;width:80%;position:relative}.img-rounded:hover{opacity:1}.footer{position:absolute;bottom:0;width:100%;border-top:1px solid #e8e8e8;padding:10px 16px;left:0;z-index:9999;background:#fff}.footer button{margin-left:10px}.m-r-10{margin-right:10px}.w-200{width:200px}.user-profile{width:200px;height:200px;background:0 0/cover #efefef;border-radius:50%}"] }] } ]; /** @nocollapse */ ProfileComponent.ctorParameters = () => [ { type: UnsubscriptionService }, { type: AngularFireAuth }, { type: AngularFirestore }, { type: NzMessageService }, { type: AngularFireStorage }, { type: AuthService }, { type: FormBuilder }, { type: NzNotificationService }, { type: HelperService } ]; ProfileComponent.propDecorators = { uploadButton: [{ type: ViewChild, args: ['uploadButton',] }], keyboardEvent: [{ type: HostListener, args: ['document:keydown', ['$event'],] }] }; if (false) { /** @type {?} */ ProfileComponent.prototype.uploadButton; /** @type {?} */ ProfileComponent.prototype.titlebar; /** @type {?} */ ProfileComponent.prototype.showChangePassword; /** @type {?} */ ProfileComponent.prototype.passwordForm; /** @type {?} */ ProfileComponent.prototype.displayNameForm; /** @type {?} */ ProfileComponent.prototype.isLoading; /** @type {?} */ ProfileComponent.prototype.showDisplayName; /** @type {?} */ ProfileComponent.prototype.profileURL; /** @type {?} */ ProfileComponent.prototype.sub; /** @type {?} */ ProfileComponent.prototype.beforeUpload; /** @type {?} */ ProfileComponent.prototype.uploadProfilePic; /** * @type {?} * @private */ ProfileComponent.prototype.unsubscription; /** * @type {?} * @private */ ProfileComponent.prototype.afAuth; /** * @type {?} * @private */ ProfileComponent.prototype.afs; /** * @type {?} * @private */ ProfileComponent.prototype.message; /** * @type {?} * @private */ ProfileComponent.prototype.storage; /** @type {?} */ ProfileComponent.prototype.auth; /** * @type {?} * @private */ ProfileComponent.prototype.fb; /** * @type {?} * @private */ ProfileComponent.prototype.notification; /** * @type {?} * @private */ ProfileComponent.prototype.helper; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZmlsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtZmlyZWJhc2UtY21zLyIsInNvdXJjZXMiOlsibGliL2NvbXBvbmVudC9wcm9maWxlL3Byb2ZpbGUuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLFVBQVUsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXZGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQzdFLE9BQU8sRUFBYSxXQUFXLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUscUJBQXFCLEVBQTZCLE1BQU0sZUFBZSxDQUFDO0FBQ25HLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzNELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDN0QsT0FBTyxLQUFLLFFBQVEsTUFBTSxjQUFjLENBQUM7QUFFekMsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMxQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQVEzRCxNQUFNLE9BQU8sZ0JBQWdCOzs7Ozs7Ozs7Ozs7SUFzQjNCLFlBQ1UsY0FBcUMsRUFDckMsTUFBdUIsRUFDdkIsR0FBcUIsRUFDckIsT0FBeUIsRUFDekIsT0FBMkIsRUFDNUIsSUFBaUIsRUFDaEIsRUFBZSxFQUNmLFlBQW1DLEVBQ25DLE1BQXFCO1FBUnJCLG1CQUFjLEdBQWQsY0FBYyxDQUF1QjtRQUNyQyxXQUFNLEdBQU4sTUFBTSxDQUFpQjtRQUN2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LENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxpQkFBaUIsQ0FBQyxDQUFBO2dCQUNyRCxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUE7YUFDdEI7U0FDRjtRQUVELElBQUksSUFBSSxDQUFDLGVBQWUsSUFBSSxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksT0FBTyxFQUFFO1lBQ3pELElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxpQkFBaUIsQ0FBQyxDQUFBO1lBQ3JELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFBO1NBQ3pCO0lBQ0gsQ0FBQzs7O1lBeEtGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsWUFBWTtnQkFDdEIsdTRIQUF1Qzs7YUFFeEM7Ozs7WUFqQlEscUJBQXFCO1lBRXJCLGVBQWU7WUFRZixnQkFBZ0I7WUFQaEIsZ0JBQWdCO1lBQ2hCLGtCQUFrQjtZQUNsQixXQUFXO1lBSkEsV0FBVztZQUVKLHFCQUFxQjtZQUd2QyxhQUFhOzs7MkJBYW5CLFNBQVMsU0FBQyxjQUFjOzRCQTJJeEIsWUFBWSxTQUFDLGtCQUFrQixFQUFFLENBQUMsUUFBUSxDQUFDOzs7O0lBM0k1Qyx3Q0FBbUQ7O0lBRW5ELG9DQVNDOztJQUVELDhDQUEwQjs7SUFDMUIsd0NBQXVCOztJQUN2QiwyQ0FBMEI7O0lBQzFCLHFDQUFpQjs7SUFDakIsMkNBQXVCOztJQUN2QixzQ0FBaUI7O0lBQ2pCLCtCQUFHOztJQXdFSCx3Q0FVQzs7SUFFRCw0Q0E4QkM7Ozs7O0lBL0dDLDBDQUE2Qzs7Ozs7SUFDN0Msa0NBQStCOzs7OztJQUMvQiwrQkFBNkI7Ozs7O0lBQzdCLG1DQUFpQzs7Ozs7SUFDakMsbUNBQW1DOztJQUNuQyxnQ0FBd0I7Ozs7O0lBQ3hCLDhCQUF1Qjs7Ozs7SUFDdkIsd0NBQTJDOzs7OztJQUMzQyxrQ0FBNkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgRWxlbWVudFJlZiwgVmlld0NoaWxkLCBIb3N0TGlzdGVuZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJyZWFkY3J1bWIgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2UvYnJlYWRjcnVtYic7XG5pbXBvcnQgeyBVbnN1YnNjcmlwdGlvblNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlL3Vuc3Vic2NyaXB0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgRm9ybUdyb3VwLCBGb3JtQnVpbGRlciwgRm9ybUNvbnRyb2wsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBBbmd1bGFyRmlyZUF1dGggfSBmcm9tICdAYW5ndWxhci9maXJlL2F1dGgnO1xuaW1wb3J0IHsgTnpNZXNzYWdlU2VydmljZSwgTnpOb3RpZmljYXRpb25TZXJ2aWNlLCBVcGxvYWRYSFJBcmdzLCBVcGxvYWRGaWxlIH0gZnJvbSAnbmctem9ycm8tYW50ZCc7XG5pbXBvcnQgeyBBbmd1bGFyRmlyZVN0b3JhZ2UgfSBmcm9tICdAYW5ndWxhci9maXJlL3N0b3JhZ2UnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlL2F1dGguc2VydmljZSc7XG5pbXBvcnQgeyBIZWxwZXJTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZS9oZWxwZXIuc2VydmljZSc7XG5pbXBvcnQgKiBhcyBmaXJlYmFzZSBmcm9tICdmaXJlYmFzZS9hcHAnO1xuaW1wb3J0IHsgSHR0cEV2ZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEFuZ3VsYXJGaXJlc3RvcmUgfSBmcm9tICdAYW5ndWxhci9maXJlL2ZpcmVzdG9yZSc7XG5pbXBvcnQgeyBUaXRsZWJhciB9IGZyb20gJy4uLy4uL2ludGVyZmFjZS90aXRsZWJhcic7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FxLXByb2ZpbGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vcHJvZmlsZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3Byb2ZpbGUuY29tcG9uZW50LmNzcyddXG59KVxuZXhwb3J0IGNsYXNzIFByb2ZpbGVDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBAVmlld0NoaWxkKCd1cGxvYWRCdXR0b24nKSB1cGxvYWRCdXR0b246IEVsZW1lbnRSZWZcblxuICB0aXRsZWJhcjogVGl0bGViYXIgPSB7XG4gICAgdGl0bGU6IFwiUHJvZmlsZVwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIkVkaXQgeW91ciBwcm9maWxlXCIsXG4gICAgYnJlYWRjcnVtYnM6IFtcbiAgICAgIHtcbiAgICAgICAgdGl0bGU6IFwiUHJvZmlsZVwiLFxuICAgICAgICBpY29uOiAndGVhbSdcbiAgICAgIH1cbiAgICBdXG4gIH1cblxuICBzaG93Q2hhbmdlUGFzc3dvcmQgPSBmYWxzZVxuICBwYXNzd29yZEZvcm06IEZvcm1Hcm91cFxuICBkaXNwbGF5TmFtZUZvcm06IEZvcm1Hcm91cFxuICBpc0xvYWRpbmcgPSBmYWxzZVxuICBzaG93RGlzcGxheU5hbWUgPSBmYWxzZVxuICBwcm9maWxlVVJMID0gbnVsbFxuICBzdWJcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHVuc3Vic2NyaXB0aW9uOiBVbnN1YnNjcmlwdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhZkF1dGg6IEFuZ3VsYXJGaXJlQXV0aCxcbiAgICBwcml2YXRlIGFmczogQW5ndWxhckZpcmVzdG9yZSxcbiAgICBwcml2YXRlIG1lc3NhZ2U6IE56TWVzc2FnZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBzdG9yYWdlOiBBbmd1bGFyRmlyZVN0b3JhZ2UsXG4gICAgcHVibGljIGF1dGg6IEF1dGhTZXJ2aWNlLFxuICAgIHByaXZhdGUgZmI6IEZvcm1CdWlsZGVyLFxuICAgIHByaXZhdGUgbm90aWZpY2F0aW9uOiBOek5vdGlmaWNhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBoZWxwZXI6IEhlbHBlclNlcnZpY2VcbiAgKSB7IH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLnN1YiA9IHRoaXMuYXV0aC51c2VyJC5zdWJzY3JpYmUocmVzID0+IHtcbiAgICAgIHRoaXMucHJvZmlsZVVSTCA9IHJlcy5wcm9maWxlVVJMXG4gICAgfSwgZXJyID0+IHt9KVxuICAgIHRoaXMuaW5pdEZvcm0oKVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5zdWIudW5zdWJzY3JpYmUoKVxuICB9XG5cbiAgaW5pdEZvcm0oKSB7XG4gICAgdGhpcy5wYXNzd29yZEZvcm0gPSB0aGlzLmZiLmdyb3VwKHtcbiAgICAgIFwicHJldmlvdXNQYXNzd29yZFwiOiBuZXcgRm9ybUNvbnRyb2woeyB2YWx1ZTogXCJcIiwgZGlzYWJsZWQ6IGZhbHNlIH0sIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSksXG4gICAgICBcIm5ld1Bhc3N3b3JkXCI6IG5ldyBGb3JtQ29udHJvbCh7IHZhbHVlOiBcIlwiLCBkaXNhYmxlZDogZmFsc2UgfSwgW1ZhbGlkYXRvcnMucmVxdWlyZWRdKSxcbiAgICB9KVxuICAgIHRoaXMuZGlzcGxheU5hbWVGb3JtID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICBcImRpc3BsYXlOYW1lXCI6IG5ldyBGb3JtQ29udHJvbCh7IFwidmFsdWVcIjogdGhpcy5hdXRoLmRpc3BsYXlOYW1lLCBkaXNhYmxlZDogZmFsc2UgfSwgW1ZhbGlkYXRvcnMucmVxdWlyZWRdKVxuICAgIH0pXG4gIH1cblxuICBjaGFuZ2VQYXNzd29yZCgpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMucGFzc3dvcmRGb3JtLnZhbHVlW1wibmV3UGFzc3dvcmRcIl0gPT0gXCJzdHJpbmdcIikgdGhpcy5wYXNzd29yZEZvcm0uY29udHJvbHNbXCJuZXdQYXNzd29yZFwiXS5zZXRWYWx1ZSh0aGlzLnBhc3N3b3JkRm9ybS52YWx1ZVtcIm5ld1Bhc3N3b3JkXCJdLnRyaW0oKSlcbiAgICBpZiAodGhpcy5wYXNzd29yZEZvcm0udmFsaWQgJiYgIXRoaXMuaXNMb2FkaW5nKSB7XG4gICAgICB0aGlzLmlzTG9hZGluZyA9IHRydWVcbiAgICAgIHRoaXMuYWZBdXRoLmF1dGguc2lnbkluV2l0aEVtYWlsQW5kUGFzc3dvcmQodGhpcy5hdXRoLmVtYWlsLCB0aGlzLnBhc3N3b3JkRm9ybS52YWx1ZVsncHJldmlvdXNQYXNzd29yZCddKS50aGVuKHJlcyA9PiB7XG4gICAgICAgIGxldCB1c2VyID0gdGhpcy5hZkF1dGguYXV0aC5jdXJyZW50VXNlclxuICAgICAgICByZXR1cm4gdXNlci51cGRhdGVQYXNzd29yZCh0aGlzLnBhc3N3b3JkRm9ybS52YWx1ZVtcIm5ld1Bhc3N3b3JkXCJdKVxuICAgICAgfSlcbiAgICAgICAgLnRoZW4ocmVzID0+IHtcbiAgICAgICAgICB0aGlzLmF1dGgubG9nKGAgdXBkYXRlZCB0aGUgcGFzc3dvcmRgKVxuICAgICAgICAgIHRoaXMubWVzc2FnZS5zdWNjZXNzKGBDaGFuZ2UgdGhlIHBhc3N3b3JkYClcbiAgICAgICAgICB0aGlzLnNob3dDaGFuZ2VQYXNzd29yZCA9ICF0aGlzLnNob3dDaGFuZ2VQYXNzd29yZFxuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2UuZXJyb3IoZXJyKVxuICAgICAgICB9KVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnBhc3N3b3JkRm9ybS5jb250cm9sc1tcIm5ld1Bhc3N3b3JkXCJdLm1hcmtBc0RpcnR5KClcbiAgICB9XG4gIH1cblxuICBjaGFuZ2VEaXNwbGF5TmFtZSgpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMuZGlzcGxheU5hbWVGb3JtLnZhbHVlW1wiZGlzcGxheU5hbWVcIl0gPT0gXCJzdHJpbmdcIikgdGhpcy5kaXNwbGF5TmFtZUZvcm0uY29udHJvbHNbXCJkaXNwbGF5TmFtZVwiXS5zZXRWYWx1ZSh0aGlzLmRpc3BsYXlOYW1lRm9ybS52YWx1ZVtcImRpc3BsYXlOYW1lXCJdLnRyaW0oKSlcbiAgICBpZiAodGhpcy5kaXNwbGF5TmFtZUZvcm0udmFsaWQgJiYgIXRoaXMuaXNMb2FkaW5nKSB7XG4gICAgICB0aGlzLmlzTG9hZGluZyA9IHRydWVcbiAgICAgIHRoaXMuYWZzLmNvbGxlY3Rpb24oXCJ1c2Vyc1wiKS5kb2ModGhpcy5hdXRoLnVpZCkudXBkYXRlKHtcbiAgICAgICAgXCJkaXNwbGF5TmFtZVwiOiB0aGlzLmRpc3BsYXlOYW1lRm9ybS52YWx1ZVtcImRpc3BsYXlOYW1lXCJdLFxuICAgICAgICBcInVwbG9hZFRpbWVcIjogZmlyZWJhc2UuZmlyZXN0b3JlLkZpZWxkVmFsdWUuc2VydmVyVGltZXN0YW1wKClcbiAgICAgIH0pLnRoZW4ocmVzID0+IHtcbiAgICAgICAgdGhpcy5pc0xvYWRpbmcgPSBmYWxzZVxuICAgICAgICB0aGlzLnNob3dEaXNwbGF5TmFtZSA9ICF0aGlzLnNob3dEaXNwbGF5TmFtZVxuICAgICAgfSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kaXNwbGF5TmFtZUZvcm0uY29udHJvbHNbXCJkaXNwbGF5TmFtZVwiXS5tYXJrQXNEaXJ0eSgpXG4gICAgfVxuICB9XG5cbiAgYmVmb3JlVXBsb2FkID0gKGZpbGU6IFVwbG9hZEZpbGUpOiBib29sZWFuID0+IHtcbiAgICBpZiAoZmlsZVsndHlwZSddICE9IFwiaW1hZ2UvanBlZ1wiKSB7XG4gICAgICB0aGlzLm1lc3NhZ2UuZXJyb3IoXCJGaWxlIHR5cGUgc2hvdWxkIGJlIEpQRUdcIilcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH0gZWxzZSBpZiAoZmlsZVsnc2l6ZSddIC8gMTAyNCAvIDEwMjQgPiAxKSB7XG4gICAgICB0aGlzLm1lc3NhZ2UuZXJyb3IoXCJGaWxlIHNpemUgc2hvdWxkIGJlIGxlc3MgdGhhbiAxIE1iXCIpXG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gIH1cblxuICB1cGxvYWRQcm9maWxlUGljID0gKGl0ZW06IFVwbG9hZFhIUkFyZ3MpID0+IHtcbiAgICB0aGlzLm1lc3NhZ2Uuc3VjY2VzcyhgRmlsZSBpcyB1cGxvYWRpbmdgKVxuICAgIGxldCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnZhbHVlT2YoKVxuICAgIGxldCBmaWxlUGF0aCA9IGAvcHJvZmlsZS8ke3RpbWVzdGFtcH0uanBlZ2BcbiAgICBsZXQgZmlsZSA9IGl0ZW1bJ2ZpbGUnXVxuICAgIGNvbnN0IHRhc2sgPSB0aGlzLnN0b3JhZ2UudXBsb2FkKGZpbGVQYXRoLCBmaWxlKVxuICAgICAgLnRoZW4ocmVzID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RvcmFnZS5yZWYoZmlsZVBhdGgpLmdldERvd25sb2FkVVJMKCkudG9Qcm9taXNlKClcbiAgICAgIH0pXG4gICAgICAudGhlbihyZXMgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5hZnMuY29sbGVjdGlvbihcInVzZXJzXCIpLmRvYyh0aGlzLmF1dGgudWlkKS51cGRhdGUoe1xuICAgICAgICAgIFwicHJvZmlsZVVSTFwiOiByZXMsXG4gICAgICAgICAgXCJ1cGxvYWRUaW1lXCI6IGZpcmViYXNlLmZpcmVzdG9yZS5GaWVsZFZhbHVlLnNlcnZlclRpbWVzdGFtcCgpXG4gICAgICAgIH0pXG4gICAgICB9KVxuICAgICAgLnRoZW4ocmVzID0+IHtcbiAgICAgICAgdGhpcy5hdXRoLmxvZyhgY2hhbmdlZCBwcm9maWxlIHBpYyAke3RpbWVzdGFtcH0uanBlZ2ApXG4gICAgICAgIHRoaXMubWVzc2FnZS5zdWNjZXNzKFwiRmlsZSBVcGxvYWRlZFwiKVxuICAgICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgdGhpcy5tZXNzYWdlLmVycm9yKGVycilcbiAgICAgIH0pXG4gICAgcmV0dXJuIG9mKCkuc3Vic2NyaWJlKChldmVudDogSHR0cEV2ZW50PHt9PikgPT4ge1xuICAgICAgaWYgKGV2ZW50WydwZXJjZW50J10gIT0gMTAwKSB7XG4gICAgICAgIGl0ZW0ub25Qcm9ncmVzcyhldmVudCwgaXRlbS5maWxlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGl0ZW0ub25TdWNjZXNzKGV2ZW50Wydib2R5J10sIGl0ZW0uZmlsZSwgZXZlbnQpO1xuICAgICAgfVxuICAgIH0sIChlcnIpID0+IHtcbiAgICAgIGl0ZW0ub25FcnJvcihlcnIsIGl0ZW0uZmlsZSk7XG4gICAgfSlcbiAgfVxuXG4gIGdldFByb2ZpbGVQaWMoKSB7XG4gICAgcmV0dXJuICh0aGlzLnByb2ZpbGVVUkwpID8geyAnYmFja2dyb3VuZC1pbWFnZSc6ICd1cmwoXFwnJyArIHRoaXMucHJvZmlsZVVSTCArICdcXCcpJyB9IDoge31cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50OmtleWRvd24nLCBbJyRldmVudCddKVxuICBrZXlib2FyZEV2ZW50KGU6IEtleWJvYXJkRXZlbnQpIHtcbiAgICBpZiAodGhpcy5zaG93Q2hhbmdlUGFzc3dvcmQgJiYgZS5rZXkgPT0gJ0VzY2FwZScpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uLmJsYW5rKFwiRVNDXCIsIFwiRXNjYXBlIG1vZGFsXCIpXG4gICAgICB0aGlzLnNob3dDaGFuZ2VQYXNzd29yZCA9IGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2hvd0Rpc3BsYXlOYW1lICYmIGUua2V5ID09ICdFc2NhcGUnKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbi5ibGFuayhcIkVTQ1wiLCBcIkVzY2FwZSBtb2RhbFwiKVxuICAgICAgdGhpcy5zaG93RGlzcGxheU5hbWUgPSBmYWxzZVxuICAgIH1cblxuICAgIGlmICh0aGlzLnNob3dDaGFuZ2VQYXNzd29yZCkge1xuICAgICAgaWYgKGUuY3RybEtleSAmJiBlLmtleSA9PSAnRW50ZXInKSB7XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uLmJsYW5rKFwi4oyDIEVOVEVSXCIsIFwiRm9ybSBTdWJtaXNzaW9uXCIpXG4gICAgICAgIHRoaXMuY2hhbmdlUGFzc3dvcmQoKVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBpZiAodGhpcy5zaG93RGlzcGxheU5hbWUgJiYgZS5jdHJsS2V5ICYmIGUua2V5ID09ICdFbnRlcicpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uLmJsYW5rKFwi4oyDIEVOVEVSXCIsIFwiRm9ybSBTdWJtaXNzaW9uXCIpXG4gICAgICB0aGlzLmNoYW5nZURpc3BsYXlOYW1lKClcbiAgICB9XG4gIH1cbn1cbiJdfQ==