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

522 lines 78.8 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';
var AuthGuard = /** @class */ (function () {
    function AuthGuard(router, authorizatorservice) {
        this.router = router;
        this.authorizatorservice = authorizatorservice;
    }
    AuthGuard.prototype.isAuthorized = function (rootFirebasePath, resource) {
        var _this = this;
        return new Observable(function (observer) {
            firebase.auth().onAuthStateChanged(function (user) {
                if (user) {
                    if (resource) {
                        Promise.all([
                            _this.authorizatorservice.getUser(rootFirebasePath, user.email),
                            _this.authorizatorservice.getRolesByUser(rootFirebasePath, user.email)
                        ]).then(function (values) {
                            var userDB = values[0];
                            var rolesDB = values[1] || [];
                            var resourcePermissionsByUser = [];
                            var resourcePermissionsByRoles = [];
                            if (userDB && userDB.data.permissions) {
                                userDB.data.permissions.filter(function (permission) { return permission.resource === resource || permission.resource === 'owner'; }).forEach(function (permission) {
                                    resourcePermissionsByUser.push(permission);
                                });
                            }
                            rolesDB.forEach(function (rolDB) {
                                if (rolDB.data.permissions) {
                                    rolDB.data.permissions.filter(function (permission) { return permission.resource === resource; }).forEach(function (permission) {
                                        resourcePermissionsByRoles.push(permission);
                                    });
                                }
                            });
                            if (resourcePermissionsByUser && resourcePermissionsByUser.length > 0 &&
                                resourcePermissionsByUser.findIndex(function (permission) { return permission.operations && permission.operations.findIndex(function (operation) { return operation === Operation.Deny; }) > -1; }) === -1) {
                                observer.next('authorized');
                            }
                            else {
                                if (resourcePermissionsByRoles && resourcePermissionsByRoles.length > 0 &&
                                    resourcePermissionsByRoles.findIndex(function (permission) { return permission.operations.findIndex(function (operation) { return operation === Operation.Deny; }) > -1; }) === -1) {
                                    observer.next('authorized');
                                }
                                else {
                                    console.error('Unauthorized resource');
                                    observer.next('unauthorized');
                                }
                            }
                        }).catch(function (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');
                }
            }, function (err) {
                observer.error(err);
            }, function () {
                observer.complete();
            });
        });
    };
    AuthGuard.prototype.canActivate = function (route, state) {
        var _this = this;
        var rootFirebasePath = route.data.rootFirebasePath;
        var resource = route.data.resource;
        var anonymousRoute = route.data.anonymousRoute || '/';
        var unauthorizedRoute = route.data.unauthorizedRoute || '/';
        var findVariable = rootFirebasePath.indexOf(':');
        if (findVariable > -1) {
            var variableEnd = rootFirebasePath.indexOf('/', findVariable);
            var variableFound_1;
            if (variableEnd > -1) {
                variableFound_1 = rootFirebasePath.substring(findVariable + 1, variableEnd);
            }
            else {
                variableFound_1 = rootFirebasePath.substring(findVariable + 1);
            }
            var existsVariable = Object.keys(route.params).findIndex(function (key) { return key === variableFound_1; });
            if (existsVariable > -1) {
                rootFirebasePath = rootFirebasePath.replace(':' + variableFound_1, route.params[variableFound_1]);
            }
        }
        return this.isAuthorized(rootFirebasePath, resource).pipe(take(1), map(function (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(function (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 = function () { return [
        { type: Router },
        { type: AuthorizatorService }
    ]; };
    AuthGuard = __decorate([
        Injectable(),
        __metadata("design:paramtypes", [Router, AuthorizatorService])
    ], AuthGuard);
    return AuthGuard;
}());
export { AuthGuard };
var AuthorizatorService = /** @class */ (function () {
    function AuthorizatorService() {
    }
    //#region Users
    AuthorizatorService.prototype.addUser = function (rootFirebasePath, user) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(user.id).get().then(function (userDB) {
                if (userDB.exists) {
                    reject({ key: 'exists', message: 'User already exists' });
                }
                else {
                    firestore.collection(path).doc(user.id).set(user.data).then(function () {
                        resolve();
                    }).catch(function (error) {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error adding user' });
                    });
                }
            });
        });
    };
    AuthorizatorService.prototype.removeUser = function (rootFirebasePath, userId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(userId).delete().then(function () {
                resolve();
            }).catch(function (error) {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error removing user' });
            });
        });
    };
    AuthorizatorService.prototype.getUser = function (rootFirebasePath, userId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(userId).get().then(function (userDB) {
                resolve({
                    id: userDB.id,
                    data: userDB.data()
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getUsers = function (rootFirebasePath) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            if (!rootFirebasePath) {
                rootFirebasePath = '';
            }
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).get().then(function (usersDB) {
                if (usersDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(usersDB.docs.map(function (userDB) {
                        return {
                            id: userDB.id,
                            data: userDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.updateUserPermissions = function (rootFirebasePath, user) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).doc(user.id).get().then(function (userDB) {
                if (!userDB.exists) {
                    reject({ key: 'notexists', message: 'User not exists' });
                }
                else {
                    firestore.collection(path).doc(user.id).update({ permissions: user.data.permissions }).then(function () {
                        resolve();
                    }).catch(function (error) {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error updating permissions' });
                    });
                }
            });
        });
    };
    //#endregion
    //#region Resources
    AuthorizatorService.prototype.addResource = function (rootFirebasePath, resource) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).add(resource.data).then(function (resourceCreated) {
                resolve(resourceCreated.id);
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.removeResource = function (rootFirebasePath, resourceId) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var resourcePath = (rootFirebasePath + '/resources').replace('//', '/');
            var usersPath = (rootFirebasePath + '/users').replace('//', '/');
            var rolesPath = (rootFirebasePath + '/roles').replace('//', '/');
            var resourceRef = firestore.collection(resourcePath).doc(resourceId);
            Promise.all([
                _this.getUsersByResource(rootFirebasePath, resourceId),
                _this.getRolesByResource(rootFirebasePath, resourceId)
            ]).then(function (values) {
                var batch = firestore.batch();
                var usersToUpdate = values[0];
                var rolesToUpdate = values[1];
                usersToUpdate.forEach(function (userToUpdate) {
                    userToUpdate.data.permissions.splice(userToUpdate.data.permissions.findIndex(function (permission) { return permission.resource === resourceId; }), 1);
                    var userRef = firestore.collection(usersPath).doc(userToUpdate.id);
                    batch.update(userRef, { data: userToUpdate.data });
                });
                rolesToUpdate.forEach(function (roleToUpdate) {
                    roleToUpdate.data.permissions.splice(roleToUpdate.data.permissions.findIndex(function (permission) { return permission.resource === resourceId; }), 1);
                    var roleRef = firestore.collection(rolesPath).doc(roleToUpdate.id);
                    batch.update(roleRef, { data: roleToUpdate.data });
                });
                batch.delete(resourceRef);
                batch.commit().then(function () {
                    resolve();
                }).catch(function (error) {
                    reject(error);
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.updateResource = function (rootFirebasePath, resource) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).doc(resource.id).set(resource.data).then(function () {
                resolve();
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getResource = function (rootFirebasePath, resourceId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).doc(resourceId).get().then(function (resourceDB) {
                resolve({
                    id: resourceDB.id,
                    data: resourceDB.data()
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getResources = function (rootFirebasePath) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/resources').replace('//', '/');
            firestore.collection(path).get().then(function (resourcesDB) {
                if (resourcesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(resourcesDB.docs.map(function (resourceDB) {
                        return {
                            id: resourceDB.id,
                            data: resourceDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    // endregion
    //#region Roles
    AuthorizatorService.prototype.addRole = function (rootFirebasePath, role) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('name', '==', role.data.name).get().then(function (roleDB) {
                if (!roleDB.empty) {
                    reject({ key: 'exists', message: 'Role already exists' });
                }
                else {
                    firestore.collection(path).add(role.data).then(function () {
                        resolve();
                    }).catch(function (error) {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error adding role' });
                    });
                }
            });
        });
    };
    AuthorizatorService.prototype.removeRole = function (rootFirebasePath, roleId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(roleId).delete().then(function () {
                resolve();
            }).catch(function (error) {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error removing role' });
            });
        });
    };
    AuthorizatorService.prototype.updateRole = function (rootFirebasePath, role) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(role.id).set(role.data).then(function () {
                resolve();
            }).catch(function (error) {
                console.error(error);
                reject({ key: 'defaulterror', message: 'Error updating role' });
            });
        });
    };
    AuthorizatorService.prototype.getRole = function (rootFirebasePath, roleId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(roleId).get().then(function (roleDB) {
                resolve({
                    id: roleDB.id,
                    data: roleDB.data()
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getRoles = function (rootFirebasePath) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            if (!rootFirebasePath) {
                rootFirebasePath = '';
            }
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).get().then(function (rolesDB) {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(function (roleDB) {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getRolesByResource = function (rootFirebasePath, resourceId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('data.resources', 'array-contains', resourceId).get().then(function (rolesDB) {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(function (roleDB) {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getRolesByUser = function (rootFirebasePath, userId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).where('users', 'array-contains', userId).get().then(function (rolesDB) {
                if (rolesDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(rolesDB.docs.map(function (roleDB) {
                        return {
                            id: roleDB.id,
                            data: roleDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.updateRolePermissions = function (rootFirebasePath, role) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            rootFirebasePath = rootFirebasePath || '';
            var path = (rootFirebasePath + '/roles').replace('//', '/');
            firestore.collection(path).doc(role.id).get().then(function (roleDB) {
                if (!roleDB.exists) {
                    reject({ key: 'notexists', message: 'Role not exists' });
                }
                else {
                    firestore.collection(path).doc(role.id).update({ permissions: role.data.permissions }).then(function () {
                        resolve();
                    }).catch(function (error) {
                        console.error(error);
                        reject({ key: 'defaulterror', message: 'Error updating permissions' });
                    });
                }
            });
        });
    };
    // endregion
    //#region Roles
    AuthorizatorService.prototype.removeUserFromRole = function (rootFirebasePath, userId) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var usersPath = (rootFirebasePath + '/users').replace('//', '/');
            var rolesPath = (rootFirebasePath + '/roles').replace('//', '/');
            _this.getRolesByUser(rootFirebasePath, userId).then(function (rolesDB) {
                var batch = firestore.batch();
                var rolesToUpdate = rolesDB;
                rolesToUpdate.forEach(function (roleToUpdate) {
                    roleToUpdate.data.users.splice(roleToUpdate.data.users.findIndex(function (user) { return user === userId; }), 1);
                    var roleRef = firestore.collection(rolesPath).doc(roleToUpdate.id);
                    batch.update(roleRef, { data: roleToUpdate.data });
                });
                var userRef = firestore.collection(usersPath).doc(userId);
                batch.delete(userRef);
                batch.commit().then(function () {
                    resolve();
                }).catch(function (error) {
                    reject(error);
                });
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService.prototype.getUsersByResource = function (rootFirebasePath, resourceId) {
        return new Promise(function (resolve, reject) {
            var firestore = firebase.firestore();
            var path = (rootFirebasePath + '/users').replace('//', '/');
            firestore.collection(path).where('data.resources', 'array-contains', resourceId).get().then(function (usersDB) {
                if (usersDB.empty) {
                    resolve(null);
                }
                else {
                    resolve(usersDB.docs.map(function (userDB) {
                        return {
                            id: userDB.id,
                            data: userDB.data()
                        };
                    }));
                }
            }).catch(function (error) {
                reject(error);
            });
        });
    };
    AuthorizatorService = __decorate([
        Injectable(),
        __metadata("design:paramtypes", [])
    ], AuthorizatorService);
    return AuthorizatorService;
}());
export { AuthorizatorService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXphdG9yLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9hbmd1bGFyLWZpcmViYXNlLWF1dGhvcml6YXRvci8iLCJzb3VyY2VzIjpbImxpYi9zZXJ2aWNlcy9hdXRob3JpemF0b3Iuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEtBQUssUUFBUSxNQUFNLFVBQVUsQ0FBQztBQUdyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNuSCxPQUFPLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUV0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDdEQsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHdkQ7SUFDRSxtQkFBb0IsTUFBYyxFQUFVLG1CQUF3QztRQUFoRSxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQVUsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFxQjtJQUFHLENBQUM7SUFFaEYsZ0NBQVksR0FBcEIsVUFBcUIsZ0JBQXdCLEVBQUUsUUFBZ0I7UUFBL0QsaUJBa0VDO1FBakVDLE9BQU8sSUFBSSxVQUFVLENBQUMsVUFBQSxRQUFRO1lBQzVCLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFBLElBQUk7Z0JBQ3JDLElBQUksSUFBSSxFQUFFO29CQUNSLElBQUksUUFBUSxFQUFFO3dCQUNaLE9BQU8sQ0FBQyxHQUFHLENBQUM7NEJBQ1YsS0FBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDOzRCQUM5RCxLQUFJLENBQUMsbUJBQW1C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QyxJQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdkMsSUFBTSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzlELFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFBLE9BQU87Z0JBQ2pHLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRTtvQkFDakIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUNmO3FCQUFNO29CQUNMLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFBLE1BQU07d0JBQzdCLE9BQU87NEJBQ0wsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFFOzRCQUNiLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxFQUFFO3lCQUNULENBQUM7b0JBQ2YsQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDTDtZQUNILENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFBLEtBQUs7Z0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hCLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBcFpVLG1CQUFtQjtRQUQvQixVQUFVLEVBQUU7O09BQ0EsbUJBQW1CLENBc1ovQjtJQUFELDBCQUFDO0NBQUEsQUF0WkQsSUFzWkM7U0F0WlksbUJBQW1CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUmVzb3VyY2VPYmogfSBmcm9tICcuLi9jbGFzc2VzL3Jlc291cmNlLW9iaic7XG5pbXBvcnQgKiBhcyBmaXJlYmFzZSBmcm9tICdmaXJlYmFzZSc7XG5pbXBvcnQgeyBSb2xlT2JqIH0gZnJvbSAnLi4vY2xhc3Nlcy9yb2xlLW9iaic7XG5pbXBvcnQgeyBVc2VyT2JqIH0gZnJvbSAnLi4vY2xhc3Nlcy91c2VyLW9iaic7XG5pbXBvcnQgeyBSb3V0ZXIsIENhbkFjdGl2YXRlLCBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90LCBSb3V0ZXJTdGF0ZVNuYXBzaG90LCBBY3RpdmF0ZWRSb3V0ZSB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgUGVybWlzc2lvbk9iaiB9IGZyb20gJy4uL2NsYXNzZXMvcGVybWlzc2lvbi1vYmonO1xuaW1wb3J0IHsgT3BlcmF0aW9uIH0gZnJvbSAnLi4vY2xhc3Nlcy9wZXJtaXNzaW9uLW9iaic7XG5pbXBvcnQgeyB0YWtlLCBtYXAsIGNhdGNoRXJyb3IgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBBdXRoR3VhcmQgaW1wbGVtZW50cyBDYW5BY3RpdmF0ZSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcm91dGVyOiBSb3V0ZXIsIHByaXZhdGUgYXV0aG9yaXphdG9yc2VydmljZTogQXV0aG9yaXphdG9yU2VydmljZSkge31cblxuICBwcml2YXRlIGlzQXV0aG9yaXplZChyb290RmlyZWJhc2VQYXRoOiBzdHJpbmcsIHJlc291cmNlOiBzdHJpbmcpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZShvYnNlcnZlciA9PiB7XG4gICAgICBmaXJlYmFzZS5hdXRoKCkub25BdXRoU3RhdGVDaGFuZ2VkKHVzZXIgPT4ge1xuICAgICAgICBpZiAodXNlcikge1xuICAgICAgICAgIGlmIChyZXNvdXJjZSkge1xuICAgICAgICAgICAgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICB0aGlzLmF1dGhvcml6YXRvcnNlcnZpY2UuZ2V0VXNlcihyb290RmlyZWJhc2VQYXRoLCB1c2VyLmVtYWlsKSxcbiAgICAgICAgICAgICAgdGhpcy5hdXRob3JpemF0b3JzZXJ2aWNlLmdldFJvbGVzQnlVc2VyKHJvb3RGaXJlYmFzZVBhdGgsIHVzZXIuZW1haWwpXG4gICAgICAgICAgICBdKS50aGVuKHZhbHVlcyA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHVzZXJEQjogVXNlck9iaiA9IHZhbHVlc1swXTtcbiAgICAgICAgICAgICAgY29uc3Qgcm9sZXNEQjogUm9sZU9ialtdID0gdmFsdWVzWzFdIHx8IFtdO1xuICAgICAgICAgICAgICBjb25zdCByZXNvdXJjZVBlcm1pc3Npb25zQnlVc2VyOiBQZXJtaXNzaW9uT2JqW10gPSBbXTtcbiAgICAgICAgICAgICAgY29uc3QgcmVzb3VyY2VQZXJtaXNzaW9uc0J5Um9sZXM6IFBlcm1pc3Npb25PYmpbXSA9IFtdO1xuICAgICAgICAgICAgICBpZiAodXNlckRCICYmIHVzZXJEQi5kYXRhLnBlcm1pc3Npb25zKSB7XG4gICAgICAgICAgICAgICAgdXNlckRCLmRhdGEucGVybWlzc2lvbnMuZmlsdGVyKFxuICAgICAgICAgICAgICAgICAgcGVybWlzc2lvbiA9PiBwZXJtaXNzaW9uLnJlc291cmNlID09PSByZXNvdXJjZSB8fCBwZXJtaXNzaW9uLnJlc291cmNlID09PSAnb3duZXInXG4gICAgICAgICAgICAgICAgKS5mb3JFYWNoKHBlcm1pc3Npb24gPT4ge1xuICAgICAgICAgICAgICAgICAgcmVzb3VyY2VQZXJtaXNzaW9uc0J5VXNlci5wdXNoKHBlcm1pc3Npb24pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJvbGVzREIuZm9yRWFjaChyb2xEQiA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHJvbERCLmRhdGEucGVybWlzc2lvbnMpIHtcbiAgICAgICAgICAgICAgICAgIHJvbERCLmRhdGEucGVybWlzc2lvbnMuZmlsdGVyKHBlcm1pc3Npb24gPT4gcGVybWlzc2lvbi5yZXNvdXJjZSA9PT0gcmVzb3VyY2UpLmZvckVhY2gocGVybWlzc2lvbiA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlc291cmNlUGVybWlzc2lvbnNCeVJvbGVzLnB1c2gocGVybWlzc2lvbik7XG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBpZiAocmVzb3VyY2VQZXJtaXNzaW9uc0J5VXNlciAmJiByZXNvdXJjZVBlcm1pc3Npb25zQnlVc2VyLmxlbmd0aCA+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=