UNPKG

angular-firebase-authorizator

Version:

Beta version of authorizator for angular linked to firebase, it creates a model in firestore to assign permissions to users an roles, and creates a view to update this permissions

515 lines 77.3 kB
import { __decorate, __metadata } from "tslib";
import { Injectable } from '@angular/core';
import * as firebase from 'firebase';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, ActivatedRoute } from '@angular/router';
import { Observable, of } from 'rxjs';
import { Operation } from '../classes/permission-obj';
import { take, map, catchError } from 'rxjs/operators';
let AuthGuard = class AuthGuard {
    constructor(router, authorizatorservice) {
        this.router = router;
        this.authorizatorservice = authorizatorservice;
    }
    isAuthorized(rootFirebasePath, resource) {
        return new Observable(observer => {
            firebase.auth().onAuthStateChanged(user => {
                if (user) {
                    if (resource) {
                        Promise.all([
                            this.authorizatorservice.getUser(rootFirebasePath, user.email),
                            this.authorizatorservice.getRolesByUser(rootFirebasePath, user.email)
                        ]).then(values => {
                            const userDB = values[0];
                            const rolesDB = values[1] || [];
                            const resourcePermissionsByUser = [];
                            const resourcePermissionsByRoles = [];
                            if (userDB && userDB.data.permissions) {
                                userDB.data.permissions.filter(permission => permission.resource === resource || permission.resource === 'owner').forEach(permission => {
                                    resourcePermissionsByUser.push(permission);
                                });
                            }
                            rolesDB.forEach(rolDB => {
                                if (rolDB.data.permissions) {
                                    rolDB.data.permissions.filter(permission => permission.resource === resource).forEach(permission => {
                                        resourcePermissionsByRoles.push(permission);
                                    });
                                }
                            });
                            if (resourcePermissionsByUser && resourcePermissionsByUser.length > 0 &&
                                resourcePermissionsByUser.findIndex(permission => permission.operations && permission.operations.findIndex(operation => operation === Operation.Deny) > -1) === -1) {
                                observer.next('authorized');
                            }
                            else {
                                if (resourcePermissionsByRoles && resourcePermissionsByRoles.length > 0 &&
                                    resourcePermissionsByRoles.findIndex(permission => permission.operations.findIndex(operation => operation === Operation.Deny) > -1) === -1) {
                                    observer.next('authorized');
                                }
                                else {
                                    console.error('Unauthorized resource');
                                    observer.next('unauthorized');
                                }
                            }
                        }).catch(error => {
                            console.error('Error getting permissions from database');
                            console.error(error);
                            observer.next('unauthorized');
                        });
                    }
                    else {
                        console.error('Resource not received');
                        observer.next('unauthorized');
                    }
                }
                else {
                    console.error('Unauthenticated user');
                    observer.next('unauthenticated');
                }
            }, err => {
                observer.error(err);
            }, () => {
                observer.complete();
            });
        });
    }
    canActivate(route, state) {
        let rootFirebasePath = route.data.rootFirebasePath;
        const resource = route.data.resource;
        const anonymousRoute = route.data.anonymousRoute || '/';
        const unauthorizedRoute = route.data.unauthorizedRoute || '/';
        const findVariable = rootFirebasePath.indexOf(':');
        if (findVariable > -1) {
            const variableEnd = rootFirebasePath.indexOf('/', findVariable);
            let variableFound;
            if (variableEnd > -1) {
                variableFound = rootFirebasePath.substring(findVariable + 1, variableEnd);
            }
            else {
                variableFound = rootFirebasePath.substring(findVariable + 1);
            }
            const existsVariable = Object.keys(route.params).findIndex(key => key === variableFound);
            if (existsVariable > -1) {
                rootFirebasePath = rootFirebasePath.replace(':' + variableFound, route.params[variableFound]);
            }
        }
        return this.isAuthorized(rootFirebasePath, resource).pipe(take(1), map(isAuth => {
            if (isAuth === 'unauthenticated') {
                this.router.navigate([anonymousRoute], { queryParams: { returnUrl: state.url } });
                return false;
            }
            if (isAuth === 'unauthorized') {
                this.router.navigate([unauthorizedRoute], { queryParams: { returnUrl: state.url } });
                return false;
            }
            if (isAuth === 'authorized') {
                return true;
            }
            return false;
        }), catchError((err) => {
            console.error('Error getting authenticated user');
            console.error(err);
            // not resource sended so redirect to unauthorized page with the return url
            this.router.navigate([anonymousRoute], { queryParams: { returnUrl: state.url } });
            return of(false);
        }));
    }
};
AuthGuard.ctorParameters = () => [
    { type: Router },
    { type: AuthorizatorService }
];
AuthGuard = __decorate([
    Injectable(),
    __metadata("design:paramtypes", [Router, AuthorizatorService])
], AuthGuard);
export { AuthGuard };
let AuthorizatorService = class AuthorizatorService {
    constructor() { }
    //#region Users
    addUser(rootFirebasePath, user) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(user.id).get().then(userDB => {
                if (userDB.exists) {
                    reject({ key: 'exists', message: 'User already exists' });
                }
                else {
                    firestore.collection(path).doc(user.id).set(user.data).then(() => {
                        resolve();
                    }).catch(error => {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error adding user' });
                    });
                }
            });
        });
    }
    removeUser(rootFirebasePath, userId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(userId).delete().then(() => {
                resolve();
            }).catch(error => {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error removing user' });
            });
        });
    }
    getUser(rootFirebasePath, userId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(userId).get().then(userDB => {
                resolve({
                    id: userDB.id,
                    data: userDB.data()
                });
            }).catch(error => {
                reject(error);
            });
        });
    }
    getUsers(rootFirebasePath) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            if (!rootFirebasePath) {
                rootFirebasePath = '';
            }
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).get().then(usersDB => {
                if (usersDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(usersDB.docs.map(userDB => {
                        return {
                            id: userDB.id,
                            data: userDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
    updateUserPermissions(rootFirebasePath, user) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(user.id).get().then(userDB => {
                if (!userDB.exists) {
                    reject({ key: 'notexists', message: 'User not exists' });
                }
                else {
                    firestore.collection(path).doc(user.id).update({ permissions: user.data.permissions }).then(() => {
                        resolve();
                    }).catch(error => {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error updating permissions' });
                    });
                }
            });
        });
    }
    //#endregion
    //#region Resources
    addResource(rootFirebasePath, resource) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).add(resource.data).then(resourceCreated => {
                resolve(resourceCreated.id);
            }).catch(error => {
                reject(error);
            });
        });
    }
    removeResource(rootFirebasePath, resourceId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const resourcePath = (rootFirebasePath + '/resources').replace('//', '/');
            const usersPath = (rootFirebasePath + '/users').replace('//', '/');
            const rolesPath = (rootFirebasePath + '/roles').replace('//', '/');
            const resourceRef = firestore.collection(resourcePath).doc(resourceId);
            Promise.all([
                this.getUsersByResource(rootFirebasePath, resourceId),
                this.getRolesByResource(rootFirebasePath, resourceId)
            ]).then(values => {
                const batch = firestore.batch();
                const usersToUpdate = values[0];
                const rolesToUpdate = values[1];
                usersToUpdate.forEach(userToUpdate => {
                    userToUpdate.data.permissions.splice(userToUpdate.data.permissions.findIndex(permission => permission.resource === resourceId), 1);
                    const userRef = firestore.collection(usersPath).doc(userToUpdate.id);
                    batch.update(userRef, { data: userToUpdate.data });
                });
                rolesToUpdate.forEach(roleToUpdate => {
                    roleToUpdate.data.permissions.splice(roleToUpdate.data.permissions.findIndex(permission => permission.resource === resourceId), 1);
                    const roleRef = firestore.collection(rolesPath).doc(roleToUpdate.id);
                    batch.update(roleRef, { data: roleToUpdate.data });
                });
                batch.delete(resourceRef);
                batch.commit().then(() => {
                    resolve();
                }).catch(error => {
                    reject(error);
                });
            }).catch(error => {
                reject(error);
            });
        });
    }
    updateResource(rootFirebasePath, resource) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).doc(resource.id).set(resource.data).then(() => {
                resolve();
            }).catch(error => {
                reject(error);
            });
        });
    }
    getResource(rootFirebasePath, resourceId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).doc(resourceId).get().then(resourceDB => {
                resolve({
                    id: resourceDB.id,
                    data: resourceDB.data()
                });
            }).catch(error => {
                reject(error);
            });
        });
    }
    getResources(rootFirebasePath) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).get().then(resourcesDB => {
                if (resourcesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(resourcesDB.docs.map(resourceDB => {
                        return {
                            id: resourceDB.id,
                            data: resourceDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
    // endregion
    //#region Roles
    addRole(rootFirebasePath, role) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('name', '==', role.data.name).get().then(roleDB => {
                if (!roleDB.empty) {
                    reject({ key: 'exists', message: 'Role already exists' });
                }
                else {
                    firestore.collection(path).add(role.data).then(() => {
                        resolve();
                    }).catch(error => {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error adding role' });
                    });
                }
            });
        });
    }
    removeRole(rootFirebasePath, roleId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(roleId).delete().then(() => {
                resolve();
            }).catch(error => {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error removing role' });
            });
        });
    }
    updateRole(rootFirebasePath, role) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(role.id).set(role.data).then(() => {
                resolve();
            }).catch(error => {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error updating role' });
            });
        });
    }
    getRole(rootFirebasePath, roleId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(roleId).get().then(roleDB => {
                resolve({
                    id: roleDB.id,
                    data: roleDB.data()
                });
            }).catch(error => {
                reject(error);
            });
        });
    }
    getRoles(rootFirebasePath) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            if (!rootFirebasePath) {
                rootFirebasePath = '';
            }
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).get().then(rolesDB => {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(roleDB => {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
    getRolesByResource(rootFirebasePath, resourceId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('data.resources', 'array-contains', resourceId).get().then(rolesDB => {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(roleDB => {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
    getRolesByUser(rootFirebasePath, userId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('users', 'array-contains', userId).get().then(rolesDB => {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(roleDB => {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
    updateRolePermissions(rootFirebasePath, role) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            const path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(role.id).get().then(roleDB => {
                if (!roleDB.exists) {
                    reject({ key: 'notexists', message: 'Role not exists' });
                }
                else {
                    firestore.collection(path).doc(role.id).update({ permissions: role.data.permissions }).then(() => {
                        resolve();
                    }).catch(error => {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error updating permissions' });
                    });
                }
            });
        });
    }
    // endregion
    //#region Roles
    removeUserFromRole(rootFirebasePath, userId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const usersPath = (rootFirebasePath + '/users').replace('//', '/');
            const rolesPath = (rootFirebasePath + '/roles').replace('//', '/');
            this.getRolesByUser(rootFirebasePath, userId).then(rolesDB => {
                const batch = firestore.batch();
                const rolesToUpdate = rolesDB;
                rolesToUpdate.forEach(roleToUpdate => {
                    roleToUpdate.data.users.splice(roleToUpdate.data.users.findIndex(user => user === userId), 1);
                    const roleRef = firestore.collection(rolesPath).doc(roleToUpdate.id);
                    batch.update(roleRef, { data: roleToUpdate.data });
                });
                const userRef = firestore.collection(usersPath).doc(userId);
                batch.delete(userRef);
                batch.commit().then(() => {
                    resolve();
                }).catch(error => {
                    reject(error);
                });
            }).catch(error => {
                reject(error);
            });
        });
    }
    getUsersByResource(rootFirebasePath, resourceId) {
        return new Promise((resolve, reject) => {
            const firestore = firebase.firestore();
            const path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).where('data.resources', 'array-contains', resourceId).get().then(usersDB => {
                if (usersDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(usersDB.docs.map(userDB => {
                        return {
                            id: userDB.id,
                            data: userDB.data()
                        };
                    }));
                }
            }).catch(error => {
                reject(error);
            });
        });
    }
};
AuthorizatorService = __decorate([
    Injectable(),
    __metadata("design:paramtypes", [])
], AuthorizatorService);
export { AuthorizatorService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXphdG9yLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9hbmd1bGFyLWZpcmViYXNlLWF1dGhvcml6YXRvci8iLCJzb3VyY2VzIjpbImxpYi9zZXJ2aWNlcy9hdXRob3JpemF0b3Iuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEtBQUssUUFBUSxNQUFNLFVBQVUsQ0FBQztBQUdyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNuSCxPQUFPLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUV0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDdEQsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHdkQsSUFBYSxTQUFTLEdBQXRCLE1BQWEsU0FBUztJQUNwQixZQUFvQixNQUFjLEVBQVUsbUJBQXdDO1FBQWhFLFdBQU0sR0FBTixNQUFNLENBQVE7UUFBVSx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXFCO0lBQUcsQ0FBQztJQUVoRixZQUFZLENBQUMsZ0JBQXdCLEVBQUUsUUFBZ0I7UUFDN0QsT0FBTyxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUMvQixRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQ3hDLElBQUksSUFBSSxFQUFFO29CQUNSLElBQUksUUFBUSxFQUFFO3dCQUNaLE9BQU8sQ0FBQyxHQUFHLENBQUM7NEJBQ1YsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDOzRCQUM5RCxJ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Q0FBQyxDQUFDO1lBQ2hCLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBRUYsQ0FBQTtBQXRaWSxtQkFBbUI7SUFEL0IsVUFBVSxFQUFFOztHQUNBLG1CQUFtQixDQXNaL0I7U0F0WlksbUJBQW1CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUmVzb3VyY2VPYmogfSBmcm9tICcuLi9jbGFzc2VzL3Jlc291cmNlLW9iaic7XG5pbXBvcnQgKiBhcyBmaXJlYmFzZSBmcm9tICdmaXJlYmFzZSc7XG5pbXBvcnQgeyBSb2xlT2JqIH0gZnJvbSAnLi4vY2xhc3Nlcy9yb2xlLW9iaic7XG5pbXBvcnQgeyBVc2VyT2JqIH0gZnJvbSAnLi4vY2xhc3Nlcy91c2VyLW9iaic7XG5pbXBvcnQgeyBSb3V0ZXIsIENhbkFjdGl2YXRlLCBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90LCBSb3V0ZXJTdGF0ZVNuYXBzaG90LCBBY3RpdmF0ZWRSb3V0ZSB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgUGVybWlzc2lvbk9iaiB9IGZyb20gJy4uL2NsYXNzZXMvcGVybWlzc2lvbi1vYmonO1xuaW1wb3J0IHsgT3BlcmF0aW9uIH0gZnJvbSAnLi4vY2xhc3Nlcy9wZXJtaXNzaW9uLW9iaic7XG5pbXBvcnQgeyB0YWtlLCBtYXAsIGNhdGNoRXJyb3IgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBBdXRoR3VhcmQgaW1wbGVtZW50cyBDYW5BY3RpdmF0ZSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcm91dGVyOiBSb3V0ZXIsIHByaXZhdGUgYXV0aG9yaXphdG9yc2VydmljZTogQXV0aG9yaXphdG9yU2VydmljZSkge31cblxuICBwcml2YXRlIGlzQXV0aG9yaXplZChyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJlc291cmNlOiBzdHJpbmcpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZShvYnNlcnZlciA9PiB7XG4gICAgICBmaXJlYmFzZS5hdXRoKCkub25BdXRoU3RhdGVDaGFuZ2VkKHVzZXIgPT4ge1xuICAgICAgICBpZiAodXNlcikge1xuICAgICAgICAgIGlmIChyZXNvdXJjZSkge1xuICAgICAgICAgICAgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICB0aGlzLmF1dGhvcml6YXRvcnNlcnZpY2UuZ2V0VXNlcihyb290RmlyZWJhc2VQYXRoLCB1c2VyLmVtYWlsKSxcbiAgICAgICAgICAgICAgdGhpcy5hdXRob3JpemF0b3JzZXJ2aWNlLmdldFJvbGVzQnlVc2VyKHJvb3RGaXJlYmFzZVBhdGgsIHVzZXIuZW1haWwpXG4gICAgICAgICAgICBdKS50aGVuKHZhbHVlcyA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHVzZXJEQjogVXNlck9iaiA9IHZhbHVlc1swXTtcbiAgICAgICAgICAgICAgY29uc3Qgcm9sZXNEQjogUm9sZU9ialtdID0gdmFsdWVzWzFdIHx8IFtdO1xuICAgICAgICAgICAgICBjb25zdCByZXNvdXJjZVBlcm1pc3Npb25zQnlVc2VyOiBQZXJtaXNzaW9uT2JqW10gPSBbXTtcbiAgICAgICAgICAgICAgY29uc3QgcmVzb3VyY2VQZXJtaXNzaW9uc0J5Um9sZXM6IFBlcm1pc3Npb25PYmpbXSA9IFtdO1xuICAgICAgICAgICAgICBpZiAodXNlckRCICYmIHVzZXJEQi5kYXRhLnBlcm1pc3Npb25zKSB7XG4gICAgICAgICAgICAgICAgdXNlckRCLmRhdGEucGVybWlzc2lvbnMuZmlsdGVyKFxuICAgICAgICAgICAgICAgICAgcGVybWlzc2lvbiA9PiBwZXJtaXNzaW9uLnJlc291cmNlID09PSByZXNvdXJjZSB8fCBwZXJtaXNzaW9uLnJlc291cmNlID09PSAnb3duZXInXG4gICAgICAgICAgICAgICAgKS5mb3JFYWNoKHBlcm1pc3Npb24gPT4ge1xuICAgICAgICAgICAgICAgICAgcmVzb3VyY2VQZXJtaXNzaW9uc0J5VXNlci5wdXNoKHBlcm1pc3Npb24pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJvbGVzREIuZm9yRWFjaChyb2xEQiA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHJvbERCLmRhdGEucGVybWlzc2lvbnMpIHtcbiAgICAgICAgICAgICAgICAgIHJvbERCLmRhdGEucGVybWlzc2lvbnMuZmlsdGVyKHBlcm1pc3Npb24gPT4gcGVybWlzc2lvbi5yZXNvdXJjZSA9PT0gcmVzb3VyY2UpLmZvckVhY2gocGVybWlzc2lvbiA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlc291cmNlUGVybWlzc2lvbnNCeVJvbGVzLnB1c2gocGVybWlzc2lvbik7XG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBpZiAocmVzb3VyY2VQZXJtaXNzaW9uc0J5VXNlciAmJiByZXNvdXJjZVBlcm1pc3Npb25zQnlVc2VyLmxlbmd0aCA+IDAgJiZcbiAgICAgICAgICAgICAgICByZXNvdXJjZVBlcm1pc3Npb25zQnlVc2VyLmZpbmRJbmRleChcbiAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb24gPT4gcGVybWlzc2lvbi5vcGVyYXRpb25zICYmIHBlcm1pc3Npb24ub3BlcmF0aW9ucy5maW5kSW5kZXgob3BlcmF0aW9uID0+IG9wZXJhdGlvbiA9PT0gT3BlcmF0aW9uLkRlbnkpID4gLTFcbiAgICAgICAgICAgICAgICApID09PSAtMVxuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQoJ2F1dGhvcml6ZWQnKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAocmVzb3VyY2VQZXJtaXNzaW9uc0J5Um9sZXMgJiYgcmVzb3VyY2VQZXJtaXNzaW9uc0J5Um9sZXMubGVuZ3RoID4gMCAmJlxuICAgICAgICAgICAgICAgICAgcmVzb3VyY2VQZXJtaXNzaW9uc0J5Um9sZXMuZmluZEluZGV4KFxuICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uID0+IHBlcm1pc3Npb24ub3BlcmF0aW9ucy5maW5kSW5kZXgob3BlcmF0aW9uID0+IG9wZXJhdGlvbiA9PT0gT3BlcmF0aW9uLkRlbnkpID4gLTFcbiAgICAgICAgICAgICAgICAgICkgPT09IC0xXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQoJ2F1dGhvcml6ZWQnKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignVW5hdXRob3JpemVkIHJlc291cmNlJyk7XG4gICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KCd1bmF1dGhvcml6ZWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZ2V0dGluZyBwZXJtaXNzaW9ucyBmcm9tIGRhdGFiYXNlJyk7XG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KCd1bmF1dGhvcml6ZWQnKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdSZXNvdXJjZSBub3QgcmVjZWl2ZWQnKTtcbiAgICAgICAgICAgIG9ic2VydmVyLm5leHQoJ3VuYXV0aG9yaXplZCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKCdVbmF1dGhlbnRpY2F0ZWQgdXNlcicpO1xuICAgICAgICAgIG9ic2VydmVyLm5leHQoJ3VuYXV0aGVudGljYXRlZCcpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgZXJyID0+IHtcbiAgICAgICAgb2JzZXJ2ZXIuZXJyb3IoZXJyKTtcbiAgICAgIH0sXG4gICAgICAoKSA9PiB7XG4gICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGNhbkFjdGl2YXRlKHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90LCBzdGF0ZTogUm91dGVyU3RhdGVTbmFwc2hvdCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIGxldCByb290RmlyZWJhc2VQYXRoOiBzdHJpbmcgPSByb3V0ZS5kYXRhLnJvb3RGaXJlYmFzZVBhdGg7XG4gICAgY29uc3QgcmVzb3VyY2UgPSByb3V0ZS5kYXRhLnJlc291cmNlO1xuICAgIGNvbnN0IGFub255bW91c1JvdXRlID0gcm91dGUuZGF0YS5hbm9ueW1vdXNSb3V0ZSB8fCAnLyc7XG4gICAgY29uc3QgdW5hdXRob3JpemVkUm91dGUgPSByb3V0ZS5kYXRhLnVuYXV0aG9yaXplZFJvdXRlIHx8ICcvJztcbiAgICBjb25zdCBmaW5kVmFyaWFibGUgPSByb290RmlyZWJhc2VQYXRoLmluZGV4T2YoJzonKTtcbiAgICBpZiAoZmluZFZhcmlhYmxlID4gLTEpIHtcbiAgICAgIGNvbnN0IHZhcmlhYmxlRW5kID0gcm9vdEZpcmViYXNlUGF0aC5pbmRleE9mKCcvJywgZmluZFZhcmlhYmxlKTtcbiAgICAgIGxldCB2YXJpYWJsZUZvdW5kO1xuICAgICAgaWYgKHZhcmlhYmxlRW5kID4gLTEpIHtcbiAgICAgICAgdmFyaWFibGVGb3VuZCA9IHJvb3RGaXJlYmFzZVBhdGguc3Vic3RyaW5nKGZpbmRWYXJpYWJsZSArIDEsIHZhcmlhYmxlRW5kKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhcmlhYmxlRm91bmQgPSByb290RmlyZWJhc2VQYXRoLnN1YnN0cmluZyhmaW5kVmFyaWFibGUgKyAxKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGV4aXN0c1ZhcmlhYmxlID0gT2JqZWN0LmtleXMocm91dGUucGFyYW1zKS5maW5kSW5kZXgoa2V5ID0+IGtleSA9PT0gdmFyaWFibGVGb3VuZCk7XG4gICAgICBpZiAoZXhpc3RzVmFyaWFibGUgPiAtMSkge1xuICAgICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aC5yZXBsYWNlKCc6JyArIHZhcmlhYmxlRm91bmQsIHJvdXRlLnBhcmFtc1t2YXJpYWJsZUZvdW5kXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaXNBdXRob3JpemVkKHJvb3RGaXJlYmFzZVBhdGgsIHJlc291cmNlKS5waXBlKFxuICAgICAgdGFrZSgxKSxcbiAgICAgIG1hcChpc0F1dGggPT4ge1xuICAgICAgICBpZiAoaXNBdXRoID09PSAndW5hdXRoZW50aWNhdGVkJykge1xuICAgICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFthbm9ueW1vdXNSb3V0ZV0sIHsgcXVlcnlQYXJhbXM6IHsgcmV0dXJuVXJsOiBzdGF0ZS51cmwgfX0pO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNBdXRoID09PSAndW5hdXRob3JpemVkJykge1xuICAgICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFt1bmF1dGhvcml6ZWRSb3V0ZV0sIHsgcXVlcnlQYXJhbXM6IHsgcmV0dXJuVXJsOiBzdGF0ZS51cmwgfX0pO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNBdXRoID09PSAnYXV0aG9yaXplZCcpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KSxcbiAgICAgIGNhdGNoRXJyb3IoKGVycikgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBnZXR0aW5nIGF1dGhlbnRpY2F0ZWQgdXNlcicpO1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgIC8vIG5vdCByZXNvdXJjZSBzZW5kZWQgc28gcmVkaXJlY3QgdG8gdW5hdXRob3JpemVkIHBhZ2Ugd2l0aCB0aGUgcmV0dXJuIHVybFxuICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbYW5vbnltb3VzUm91dGVdLCB7IHF1ZXJ5UGFyYW1zOiB7IHJldHVyblVybDogc3RhdGUudXJsIH19KTtcbiAgICAgICAgcmV0dXJuIG9mKGZhbHNlKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxufVxuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgQXV0aG9yaXphdG9yU2VydmljZSB7XG5cbiAgY29uc3RydWN0b3IoKSB7IH1cblxuICAvLyNyZWdpb24gVXNlcnNcbiAgYWRkVXNlcihyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHVzZXI6IFVzZXJPYmopOiBQcm9taXNlPG51bGw+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aCB8fCAnJztcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvdXNlcnMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2ModXNlci5pZCkuZ2V0KCkudGhlbih1c2VyREIgPT4ge1xuICAgICAgICBpZiAodXNlckRCLmV4aXN0cykge1xuICAgICAgICAgIHJlamVjdCh7IGtleTogJ2V4aXN0cycsIG1lc3NhZ2U6ICdVc2VyIGFscmVhZHkgZXhpc3RzJyB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2ModXNlci5pZCkuc2V0KHVzZXIuZGF0YSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICByZWplY3QoIHsga2V5OiAnZGVmYXVsdGVycm9yJywgbWVzc2FnZTogJ0Vycm9yIGFkZGluZyB1c2VyJyB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICByZW1vdmVVc2VyKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZywgdXNlcklkOiBzdHJpbmcpOiBQcm9taXNlPG51bGw+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aCB8fCAnJztcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvdXNlcnMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2ModXNlcklkKS5kZWxldGUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgcmVqZWN0KCB7IGtleTogJ2RlZmF1bHRlcnJvcicsIG1lc3NhZ2U6ICdFcnJvciByZW1vdmluZyB1c2VyJyB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgZ2V0VXNlcihyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxVc2VyT2JqPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGZpcmVzdG9yZSA9IGZpcmViYXNlLmZpcmVzdG9yZSgpO1xuICAgICAgY29uc3QgcGF0aCA9IChyb290RmlyZWJhc2VQYXRoICsgJy91c2VycycpLnJlcGxhY2UoJy8vJywgJy8nKTtcbiAgICAgIGZpcmVzdG9yZS5jb2xsZWN0aW9uKHBhdGgpLmRvYyh1c2VySWQpLmdldCgpLnRoZW4odXNlckRCID0+IHtcbiAgICAgICAgcmVzb2x2ZSh7XG4gICAgICAgICAgaWQ6IHVzZXJEQi5pZCxcbiAgICAgICAgICBkYXRhOiB1c2VyREIuZGF0YSgpXG4gICAgICAgIH0gYXMgVXNlck9iaik7XG4gICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldFVzZXJzKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZyk6IFByb21pc2U8VXNlck9ialtdPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGZpcmVzdG9yZSA9IGZpcmViYXNlLmZpcmVzdG9yZSgpO1xuICAgICAgaWYgKCFyb290RmlyZWJhc2VQYXRoKSB7XG4gICAgICAgIHJvb3RGaXJlYmFzZVBhdGggPSAnJztcbiAgICAgIH1cbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvdXNlcnMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5nZXQoKS50aGVuKHVzZXJzREIgPT4ge1xuICAgICAgICBpZiAodXNlcnNEQi5lbXB0eSkge1xuICAgICAgICAgIHJlc29sdmUobnVsbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzb2x2ZSh1c2Vyc0RCLmRvY3MubWFwKHVzZXJEQiA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBpZDogdXNlckRCLmlkLFxuICAgICAgICAgICAgICBkYXRhOiB1c2VyREIuZGF0YSgpXG4gICAgICAgICAgICB9IGFzIFVzZXJPYmo7XG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG4gICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHVwZGF0ZVVzZXJQZXJtaXNzaW9ucyhyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHVzZXI6IFVzZXJPYmopIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aCB8fCAnJztcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvdXNlcnMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2ModXNlci5pZCkuZ2V0KCkudGhlbih1c2VyREIgPT4ge1xuICAgICAgICBpZiAoIXVzZXJEQi5leGlzdHMpIHtcbiAgICAgICAgICByZWplY3QoeyBrZXk6ICdub3RleGlzdHMnLCBtZXNzYWdlOiAnVXNlciBub3QgZXhpc3RzJyB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2ModXNlci5pZCkudXBkYXRlKFxuICAgICAgICAgICAgeyBwZXJtaXNzaW9uczogdXNlci5kYXRhLnBlcm1pc3Npb25zIH1cbiAgICAgICAgICApLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgcmVqZWN0KCB7IGtleTogJ2RlZmF1bHRlcnJvcicsIG1lc3NhZ2U6ICdFcnJvciB1cGRhdGluZyBwZXJtaXNzaW9ucycgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIC8vI2VuZHJlZ2lvblxuXG4gIC8vI3JlZ2lvbiBSZXNvdXJjZXNcbiAgYWRkUmVzb3VyY2Uocm9vdEZpcmViYXNlUGF0aDogc3RyaW5nLCByZXNvdXJjZTogUmVzb3VyY2VPYmopOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcmVzb3VyY2VzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgZmlyZXN0b3JlLmNvbGxlY3Rpb24ocGF0aCkuYWRkKHJlc291cmNlLmRhdGEpLnRoZW4ocmVzb3VyY2VDcmVhdGVkID0+IHtcbiAgICAgICAgcmVzb2x2ZShyZXNvdXJjZUNyZWF0ZWQuaWQpO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICByZW1vdmVSZXNvdXJjZShyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJlc291cmNlSWQ6IHN0cmluZyk6IFByb21pc2U8bnVsbD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHJlc291cmNlUGF0aCA9IChyb290RmlyZWJhc2VQYXRoICsgJy9yZXNvdXJjZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBjb25zdCB1c2Vyc1BhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvdXNlcnMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBjb25zdCByb2xlc1BhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBjb25zdCByZXNvdXJjZVJlZiA9IGZpcmVzdG9yZS5jb2xsZWN0aW9uKHJlc291cmNlUGF0aCkuZG9jKHJlc291cmNlSWQpO1xuICAgICAgUHJvbWlzZS5hbGwoW1xuICAgICAgICB0aGlzLmdldFVzZXJzQnlSZXNvdXJjZShyb290RmlyZWJhc2VQYXRoLCByZXNvdXJjZUlkKSxcbiAgICAgICAgdGhpcy5nZXRSb2xlc0J5UmVzb3VyY2Uocm9vdEZpcmViYXNlUGF0aCwgcmVzb3VyY2VJZClcbiAgICAgIF0pLnRoZW4odmFsdWVzID0+IHtcbiAgICAgICAgY29uc3QgYmF0Y2ggPSBmaXJlc3RvcmUuYmF0Y2goKTtcbiAgICAgICAgY29uc3QgdXNlcnNUb1VwZGF0ZTogVXNlck9ialtdID0gdmFsdWVzWzBdO1xuICAgICAgICBjb25zdCByb2xlc1RvVXBkYXRlOiBSb2xlT2JqW10gPSB2YWx1ZXNbMV07XG4gICAgICAgIHVzZXJzVG9VcGRhdGUuZm9yRWFjaCh1c2VyVG9VcGRhdGUgPT4ge1xuICAgICAgICAgIHVzZXJUb1VwZGF0ZS5kYXRhLnBlcm1pc3Npb25zLnNwbGljZShcbiAgICAgICAgICAgIHVzZXJUb1VwZGF0ZS5kYXRhLnBlcm1pc3Npb25zLmZpbmRJbmRleChwZXJtaXNzaW9uID0+IHBlcm1pc3Npb24ucmVzb3VyY2UgPT09IHJlc291cmNlSWQpLCAxXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCB1c2VyUmVmID0gZmlyZXN0b3JlLmNvbGxlY3Rpb24odXNlcnNQYXRoKS5kb2ModXNlclRvVXBkYXRlLmlkKTtcbiAgICAgICAgICBiYXRjaC51cGRhdGUodXNlclJlZiwgeyBkYXRhOiB1c2VyVG9VcGRhdGUuZGF0YSB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJvbGVzVG9VcGRhdGUuZm9yRWFjaChyb2xlVG9VcGRhdGUgPT4ge1xuICAgICAgICAgIHJvbGVUb1VwZGF0ZS5kYXRhLnBlcm1pc3Npb25zLnNwbGljZShcbiAgICAgICAgICAgIHJvbGVUb1VwZGF0ZS5kYXRhLnBlcm1pc3Npb25zLmZpbmRJbmRleChwZXJtaXNzaW9uID0+IHBlcm1pc3Npb24ucmVzb3VyY2UgPT09IHJlc291cmNlSWQpLCAxXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCByb2xlUmVmID0gZmlyZXN0b3JlLmNvbGxlY3Rpb24ocm9sZXNQYXRoKS5kb2Mocm9sZVRvVXBkYXRlLmlkKTtcbiAgICAgICAgICBiYXRjaC51cGRhdGUocm9sZVJlZiwgeyBkYXRhOiByb2xlVG9VcGRhdGUuZGF0YSB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGJhdGNoLmRlbGV0ZShyZXNvdXJjZVJlZik7XG4gICAgICAgIGJhdGNoLmNvbW1pdCgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICB1cGRhdGVSZXNvdXJjZShyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJlc291cmNlOiBSZXNvdXJjZU9iaik6IFByb21pc2U8bnVsbD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcmVzb3VyY2VzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgZmlyZXN0b3JlLmNvbGxlY3Rpb24ocGF0aCkuZG9jKHJlc291cmNlLmlkKS5zZXQocmVzb3VyY2UuZGF0YSkudGhlbigoKSA9PiB7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgZ2V0UmVzb3VyY2Uocm9vdEZpcmViYXNlUGF0aDogc3RyaW5nLCByZXNvdXJjZUlkOiBzdHJpbmcpOiBQcm9taXNlPFJlc291cmNlT2JqPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGZpcmVzdG9yZSA9IGZpcmViYXNlLmZpcmVzdG9yZSgpO1xuICAgICAgY29uc3QgcGF0aCA9IChyb290RmlyZWJhc2VQYXRoICsgJy9yZXNvdXJjZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2MocmVzb3VyY2VJZCkuZ2V0KCkudGhlbihyZXNvdXJjZURCID0+IHtcbiAgICAgICAgcmVzb2x2ZSh7XG4gICAgICAgICAgaWQ6IHJlc291cmNlREIuaWQsXG4gICAgICAgICAgZGF0YTogcmVzb3VyY2VEQi5kYXRhKClcbiAgICAgICAgfSBhcyBSZXNvdXJjZU9iaik7XG4gICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldFJlc291cmNlcyhyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFJlc291cmNlT2JqW10+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICBjb25zdCBwYXRoID0gKHJvb3RGaXJlYmFzZVBhdGggKyAnL3Jlc291cmNlcycpLnJlcGxhY2UoJy8vJywgJy8nKTtcbiAgICAgIGZpcmVzdG9yZS5jb2xsZWN0aW9uKHBhdGgpLmdldCgpLnRoZW4ocmVzb3VyY2VzREIgPT4ge1xuICAgICAgICBpZiAocmVzb3VyY2VzREIuZW1wdHkpIHtcbiAgICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc29sdmUocmVzb3VyY2VzREIuZG9jcy5tYXAocmVzb3VyY2VEQiA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBpZDogcmVzb3VyY2VEQi5pZCxcbiAgICAgICAgICAgICAgZGF0YTogcmVzb3VyY2VEQi5kYXRhKClcbiAgICAgICAgICAgIH0gYXMgUmVzb3VyY2VPYmo7XG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG4gICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvLyBlbmRyZWdpb25cblxuICAvLyNyZWdpb24gUm9sZXNcbiAgYWRkUm9sZShyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJvbGU6IFJvbGVPYmopOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIHJvb3RGaXJlYmFzZVBhdGggPSByb290RmlyZWJhc2VQYXRoIHx8ICcnO1xuICAgICAgY29uc3QgcGF0aCA9IChyb290RmlyZWJhc2VQYXRoICsgJy9yb2xlcycpLnJlcGxhY2UoJy8vJywgJy8nKTtcbiAgICAgIGZpcmVzdG9yZS5jb2xsZWN0aW9uKHBhdGgpLndoZXJlKCduYW1lJywgJz09Jywgcm9sZS5kYXRhLm5hbWUpLmdldCgpLnRoZW4ocm9sZURCID0+IHtcbiAgICAgICAgaWYgKCFyb2xlREIuZW1wdHkpIHtcbiAgICAgICAgICByZWplY3QoeyBrZXk6ICdleGlzdHMnLCBtZXNzYWdlOiAnUm9sZSBhbHJlYWR5IGV4aXN0cycgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZmlyZXN0b3JlLmNvbGxlY3Rpb24ocGF0aCkuYWRkKHJvbGUuZGF0YSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICByZWplY3QoIHsga2V5OiAnZGVmYXVsdGVycm9yJywgbWVzc2FnZTogJ0Vycm9yIGFkZGluZyByb2xlJyB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICByZW1vdmVSb2xlKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZywgcm9sZUlkOiBzdHJpbmcpOiBQcm9taXNlPG51bGw+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aCB8fCAnJztcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2Mocm9sZUlkKS5kZWxldGUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgcmVqZWN0KCB7IGtleTogJ2RlZmF1bHRlcnJvcicsIG1lc3NhZ2U6ICdFcnJvciByZW1vdmluZyByb2xlJyB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgdXBkYXRlUm9sZShyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJvbGU6IFJvbGVPYmopOiBQcm9taXNlPG51bGw+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICByb290RmlyZWJhc2VQYXRoID0gcm9vdEZpcmViYXNlUGF0aCB8fCAnJztcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2Mocm9sZS5pZCkuc2V0KHJvbGUuZGF0YSkudGhlbigoKSA9PiB7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgIHJlamVjdCggeyBrZXk6ICdkZWZhdWx0ZXJyb3InLCBtZXNzYWdlOiAnRXJyb3IgdXBkYXRpbmcgcm9sZScgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldFJvbGUocm9vdEZpcmViYXNlUGF0aDogc3RyaW5nLCByb2xlSWQ6IHN0cmluZyk6IFByb21pc2U8Um9sZU9iaj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS5kb2Mocm9sZUlkKS5nZXQoKS50aGVuKHJvbGVEQiA9PiB7XG4gICAgICAgIHJlc29sdmUoe1xuICAgICAgICAgIGlkOiByb2xlREIuaWQsXG4gICAgICAgICAgZGF0YTogcm9sZURCLmRhdGEoKVxuICAgICAgICB9IGFzIFJvbGVPYmopO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBnZXRSb2xlcyhyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFJvbGVPYmpbXT4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGlmICghcm9vdEZpcmViYXNlUGF0aCkge1xuICAgICAgICByb290RmlyZWJhc2VQYXRoID0gJyc7XG4gICAgICB9XG4gICAgICBjb25zdCBwYXRoID0gKHJvb3RGaXJlYmFzZVBhdGggKyAnL3JvbGVzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgZmlyZXN0b3JlLmNvbGxlY3Rpb24ocGF0aCkuZ2V0KCkudGhlbihyb2xlc0RCID0+IHtcbiAgICAgICAgaWYgKHJvbGVzREIuZW1wdHkpIHtcbiAgICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc29sdmUocm9sZXNEQi5kb2NzLm1hcChyb2xlREIgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgaWQ6IHJvbGVEQi5pZCxcbiAgICAgICAgICAgICAgZGF0YTogcm9sZURCLmRhdGEoKVxuICAgICAgICAgICAgfSBhcyBSb2xlT2JqO1xuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBnZXRSb2xlc0J5UmVzb3VyY2Uocm9vdEZpcmViYXNlUGF0aDogc3RyaW5nLCByZXNvdXJjZUlkOiBzdHJpbmcpOiBQcm9taXNlPFJvbGVPYmpbXT4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS53aGVyZSgnZGF0YS5yZXNvdXJjZXMnLCAnYXJyYXktY29udGFpbnMnLCByZXNvdXJjZUlkKS5nZXQoKS50aGVuKHJvbGVzREIgPT4ge1xuICAgICAgICBpZiAocm9sZXNEQi5lbXB0eSkge1xuICAgICAgICAgIHJlc29sdmUobnVsbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzb2x2ZShyb2xlc0RCLmRvY3MubWFwKHJvbGVEQiA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBpZDogcm9sZURCLmlkLFxuICAgICAgICAgICAgICBkYXRhOiByb2xlREIuZGF0YSgpXG4gICAgICAgICAgICB9IGFzIFJvbGVPYmo7XG4gICAgICAgICAgfSkpO1xuICAgICAgICB9XG4gICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGdldFJvbGVzQnlVc2VyKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZywgdXNlcklkOiBzdHJpbmcpOiBQcm9taXNlPFJvbGVPYmpbXT4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIGNvbnN0IHBhdGggPSAocm9vdEZpcmViYXNlUGF0aCArICcvcm9sZXMnKS5yZXBsYWNlKCcvLycsICcvJyk7XG4gICAgICBmaXJlc3RvcmUuY29sbGVjdGlvbihwYXRoKS53aGVyZSgndXNlcnMnLCAnYXJyYXktY29udGFpbnMnLCB1c2VySWQpLmdldCgpLnRoZW4ocm9sZXNEQiA9PiB7XG4gICAgICAgIGlmIChyb2xlc0RCLmVtcHR5KSB7XG4gICAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNvbHZlKHJvbGVzREIuZG9jcy5tYXAocm9sZURCID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGlkOiByb2xlREIuaWQsXG4gICAgICAgICAgICAgIGRhdGE6IHJvbGVEQi5kYXRhKClcbiAgICAgICAgICAgIH0gYXMgUm9sZU9iajtcbiAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgdXBkYXRlUm9sZVBlcm1pc3Npb25zKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZywgcm9sZTogUm9sZU9iaikge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBmaXJlc3RvcmUgPSBmaXJlYmFzZS5maXJlc3RvcmUoKTtcbiAgICAgIHJvb3RGaXJlYmFzZVBhdGggPSByb290RmlyZWJhc2VQYXRoIHx8ICcnO1xuICAgICAgY29uc3QgcGF0aCA9IChyb290RmlyZWJhc2VQYXRoICsgJy9yb2xlcycpLnJlcGxhY2UoJy8vJywgJy8nKTtcbiAgICAgIGZpcmVzdG9yZS5jb2xsZWN0aW9uKHBhdGgpLmRvYyhyb2xlLmlkKS5nZXQoKS50aGVuKHJvbGVEQiA9PiB7XG4gICAgICAgIGlmICghcm9sZURCLmV4aXN0cykge1xuICAgICAgICAgIHJlamVjdCh7IGtleTogJ25vdGV4aXN0cycsIG1lc3NhZ2U6ICdSb2xlIG5vdCBleGlzdHMnIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZpcmVzdG9yZS5jb2xsZWN0aW9uKHBhdGgpLmRvYyhyb2xlLmlkKS51cGRhdGUoXG4gICAgICAgICAgICB7IHBlcm1pc3Npb25zOiByb2xlLmRhdGEucGVybWlzc2lvbnMgfVxuICAgICAgICAgICkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICByZWplY3QoIHsga2V5OiAnZGVmYXVsdGVycm9yJywgbWVzc2FnZTogJ0Vycm9yIHVwZGF0aW5nIHBlcm1pc3Npb25zJyB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgLy8gZW5kcmVnaW9uXG5cbiAgLy8jcmVnaW9uIFJvbGVzXG4gIHJlbW92ZVVzZXJGcm9tUm9sZShyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxudWxsPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGZpcmVzdG9yZSA9IGZpcmViYXNlLmZpcmVzdG9yZSgpO1xuICAgICAgY29uc3QgdXNlcnNQYXRoID0gKHJvb3RGaXJlYmFzZVBhdGggKyAnL3VzZXJzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgY29uc3Qgcm9sZXNQYXRoID0gKHJvb3RGaXJlYmFzZVBhdGggKyAnL3JvbGVzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgdGhpcy5nZXRSb2xlc0J5VXNlcihyb290RmlyZWJhc2VQYXRoLCB1c2VySWQpLnRoZW4ocm9sZXNEQiA9PiB7XG4gICAgICAgIGNvbnN0IGJhdGNoID0gZmlyZXN0b3JlLmJhdGNoKCk7XG4gICAgICAgIGNvbnN0IHJvbGVzVG9VcGRhdGU6IFJvbGVPYmpbXSA9IHJvbGVzREI7XG4gICAgICAgIHJvbGVzVG9VcGRhdGUuZm9yRWFjaChyb2xlVG9VcGRhdGUgPT4ge1xuICAgICAgICAgIHJvbGVUb1VwZGF0ZS5kYXRhLnVzZXJzLnNwbGljZShyb2xlVG9VcGRhdGUuZGF0YS51c2Vycy5maW5kSW5kZXgodXNlciA9PiB1c2VyID09PSB1c2VySWQpLCAxKTtcbiAgICAgICAgICBjb25zdCByb2xlUmVmID0gZmlyZXN0b3JlLmNvbGxlY3Rpb24ocm9sZXNQYXRoKS5kb2Mocm9sZVRvVXBkYXRlLmlkKTtcbiAgICAgICAgICBiYXRjaC51cGRhdGUocm9sZVJlZiwgeyBkYXRhOiByb2xlVG9VcGRhdGUuZGF0YSB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHVzZXJSZWYgPSBmaXJlc3RvcmUuY29sbGVjdGlvbih1c2Vyc1BhdGgpLmRvYyh1c2VySWQpO1xuICAgICAgICBiYXRjaC5kZWxldGUodXNlclJlZik7XG4gICAgICAgIGJhdGNoLmNvbW1pdCgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuXG5cbiAgZ2V0VXNlcnNCeVJlc291cmNlKHJvb3RGaXJlYmFzZVBhdGg6IHN0cmluZywgcmVzb3VyY2VJZDogc3RyaW5nKTogUHJvbWlzZTxVc2VyT2JqW10+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgZmlyZXN0b3JlID0gZmlyZWJhc2UuZmlyZXN0b3JlKCk7XG4gICAgICBjb25zdCBwYXRoID0gKHJvb3RGaXJlYmFzZVBhdGggKyAnL3VzZXJzJykucmVwbGFjZSgnLy8nLCAnLycpO1xuICAgICAgZmlyZXN0b3JlLmNvbGxlY3Rpb24ocGF0aCkud2hlcmUoJ2RhdGEucmVzb3VyY2VzJywgJ2FycmF5LWNvbnRhaW5zJywgcmVzb3VyY2VJZCkuZ2V0KCkudGhlbih1c2Vyc0RCID0+IHtcbiAgICAgICAgaWYgKHVzZXJzREIuZW1wdHkpIHtcbiAgICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc29sdmUodXNlcnNEQi5kb2NzLm1hcCh1c2VyREIgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgaWQ6IHVzZXJEQi5pZCxcbiAgICAgICAgICAgICAgZGF0YTogdXNlckRCLmRhdGEoKVxuICAgICAgICAgICAgfSBhcyBVc2VyT2JqO1xuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgLy8gZW5kcmVnaW9uXG59XG4iXX0=