UNPKG

firebase-bolt

Version:

Firebase Bolt Security and Modeling Language Compiler

419 lines (418 loc) 69.4 kB
"use strict"; exports.__esModule = true; /* * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var bolt = require("../bolt"); var parse = bolt.parse; var generator = require("../rules-generator"); var ast = require("../ast"); var fileio = require("../file-io"); var logger = require("../logger"); var helper = require("./test-helper"); var sample_files_1 = require("./sample-files"); var chai = require("chai"); chai.config.truncateThreshold = 1000; var assert = chai.assert; // TODO: Test duplicated function, and schema definitions. // TODO: Test other parser errors - appropriate messages (exceptions). suite("Rules Generator Tests", function () { suite("Basic Samples", function () { var tests = [ { data: "path / {read() { true } write() { true }}", expect: { rules: { ".read": "true", ".write": "true" } } }, { data: "path / { write() { true }}", expect: { rules: { ".write": "true" } } }, { data: "path / { create() { true }}", expect: { rules: { ".write": "data.val() == null" } } }, { data: "path / { update() { true }}", expect: { rules: { ".write": "(data.val() != null && newData.val() != null)" } } }, { data: "path / { delete() { true }}", expect: { rules: { ".write": "(data.val() != null && newData.val() == null)" } } }, { data: "path / {read() { true }}", expect: { rules: { ".read": "true" } } }, { data: "path / { read() { false }}", expect: { rules: {} } }, { data: "path / {index() { return ['a', 'b']; }}", expect: { rules: { ".indexOn": ["a", "b"] } } }, { data: "path / { validate() { return this > 0; }}", expect: { rules: { ".validate": "newData.val() > 0" } } }, ]; helper.dataDrivenTest(tests, function (data, expect) { var result = parse(data); assert.ok(result); var gen = new bolt.Generator(result); var json = gen.generateRules(); assert.deepEqual(json, expect); }); }); suite("Sample files", function () { helper.dataDrivenTest(sample_files_1.samples, function (filename) { filename = 'samples/' + filename + '.' + bolt.FILE_EXTENSION; return fileio.readFile(filename) .then(function (response) { var result = parse(response.content); assert.ok(result, response.url); var gen = new bolt.Generator(result); var json = gen.generateRules(); assert.ok('rules' in json, response.url + " has rules"); return fileio.readJSONFile(response.url.replace('.' + bolt.FILE_EXTENSION, '.json')) .then(function (response2) { assert.deepEqual(json, response2); }); })["catch"](function (error) { assert.ok(false, error.message); }); }); }); suite("Partial evaluation", function () { var tests = [ { f: "function f(a) { return true == a; }", x: "f(a == b)", expect: "true == (a == b)" }, { f: "function f(a) { return a == true; }", x: "f(a == b)", expect: "a == b == true" }, { f: "function f(a) { return a + 3; }", x: "f(1 + 2)", expect: "1 + 2 + 3" }, { f: "function f(a) { return a + 3; }", x: "f(1 * 2)", expect: "1 * 2 + 3" }, { f: "function f(a) { return a * 3; }", x: "f(1 + 2)", expect: "(1 + 2) * 3" }, { f: "function f(a) { return a + 1; }", x: "f(a + a)", expect: "a + a + 1" }, { f: "function f(a) { return g(a); } function g(a) { return a == true; }", x: "f(123)", expect: "123 == true" }, { f: "function f(a, b) { return g(a) == g(b); } function g(a) { return a == true; }", x: "f(1, 2)", expect: "1 == true == (2 == true)" }, // Highler level function works as long as returns a constant function { f: "function f() { return g; } function g(a) { return a == true; }", x: "f()(123)", expect: "123 == true" }, { f: "function f(a) { return a + 1; }", x: "a[f(123)]", expect: "a[123 + 1]" }, { f: "", x: "this", expect: "newData.val() == true" }, { f: "", x: "!this", expect: "!(newData.val() == true)" }, { f: "", x: "this.prop", expect: "newData.child('prop').val() == true" }, { f: "", x: "!this.prop", expect: "!(newData.child('prop').val() == true)" }, { f: "", x: "this.foo.parent()", expect: "newData.child('foo').parent().val() == true" }, { f: "", x: "this.foo || this.bar", expect: "(newData.child('foo').val() == true || newData.child('bar').val() == true)" }, // TODO: Don't support snapshot functions beyond parent. // TODO: Should warn user not to use Firebase builtins! // { f: "", x: "this.isString()", expect: "newData.child('isString').val() == true" }, { f: "function f(a) { return a == '123'; }", x: "f(this)", expect: "newData.val() == '123'" }, { f: "function f(a) { return a == '123'; }", x: "f(this.foo)", expect: "newData.child('foo').val() == '123'" }, ]; helper.dataDrivenTest(tests, function (data, expect) { var symbols = parse(data.f + " path /x { write() { return " + data.x + "; }}"); var gen = new bolt.Generator(symbols); // Make sure local Schema initialized. var json = gen.generateRules(); assert.equal(json['rules']['x']['.write'], expect); }); }); suite("String methods", function () { var tests = [ { data: "this.length", expect: "newData.val().length" }, { data: "this.length < 100", expect: "newData.val().length < 100" }, { data: "'abc'.length", expect: "'abc'.length" }, { data: "'abc'.includes('b')", expect: "'abc'.contains('b')" }, { data: "this.includes('b')", expect: "newData.val().contains('b')" }, { data: "'abc'.includes(this)", expect: "'abc'.contains(newData.val())" }, { data: "'abc'.startsWith(this)", expect: "'abc'.beginsWith(newData.val())" }, { data: "'abc'.endsWith(this)", expect: "'abc'.endsWith(newData.val())" }, { data: "'abc'.replace(this.a, this.b)", expect: "'abc'.replace(newData.child('a').val(), newData.child('b').val())" }, { data: "'ABC'.toLowerCase()", expect: "'ABC'.toLowerCase()" }, { data: "'abc'.toUpperCase()", expect: "'abc'.toUpperCase()" }, { data: "this.toUpperCase()", expect: "newData.val().toUpperCase()" }, { data: "'ababa'.test(/bab/)", expect: "'ababa'.matches(/bab/)" }, ]; helper.dataDrivenTest(tests, function (data, expect) { var symbols = parse("path /x { write() { return " + data + "; }}"); var gen = new bolt.Generator(symbols); // Make sure local Schema initialized. var json = gen.generateRules(); assert.equal(json['rules']['x']['.write'], expect); }); }); suite("Builtin validation functions", function () { var tests = [ ['String', 'this.isString()'], ['Number', 'this.isNumber()'], ['Boolean', 'this.isBoolean()'], ['Object', 'this.hasChildren()'], ['Null', 'false'], ]; helper.dataDrivenTest(tests, function (data, expect) { var symbols = parse("path / {}"); var gen = new bolt.Generator(symbols); gen.ensureValidator(ast.typeType(data)); var terms = gen.validators[data]['.validate']; var result = bolt.decodeExpression(ast.andArray(terms)); assert.deepEqual(result, expect); }); }); suite("Schema Validation", function () { var tests = [ { data: "type T {}", expect: undefined }, { data: "type T extends Object {}", expect: { '.validate': "newData.hasChildren()" } }, { data: "type T extends String {}", expect: { '.validate': "newData.isString()" } }, { data: "type T extends String { validate() { return this.length > 0; } }", expect: { '.validate': "(newData.isString() && newData.val().length > 0)" } }, { data: "type NonEmpty extends String { validate() { return this.length > 0; } } \ type T { prop: NonEmpty }", expect: { '.validate': "newData.hasChildren(['prop'])", prop: { '.validate': '(newData.isString() && newData.val().length > 0)' }, '$other': { '.validate': "false" } } }, { data: "type T {n: Number}", expect: { '.validate': "newData.hasChildren(['n'])", n: { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } } }, { data: "type T {s: String}", expect: { '.validate': "newData.hasChildren(['s'])", s: { '.validate': "newData.isString()" }, '$other': { '.validate': "false" } } }, { data: "type T {b: Boolean}", expect: { '.validate': "newData.hasChildren(['b'])", b: { '.validate': "newData.isBoolean()" }, '$other': { '.validate': "false" } } }, { data: "type T {x: Object}", expect: { '.validate': "newData.hasChildren(['x'])", x: { '.validate': "newData.hasChildren()" }, '$other': { '.validate': "false" } } }, { data: "type T {x: Number|String}", expect: { '.validate': "newData.hasChildren(['x'])", x: { '.validate': "(newData.isNumber() || newData.isString())" }, '$other': { '.validate': "false" } } }, { data: "type T { $key: Number }", expect: { '.validate': "newData.hasChildren()", '$key': { '.validate': "newData.isNumber()" } } }, { data: "type T { 'a b': Number }", expect: { '.validate': "newData.hasChildren(['a b'])", 'a b': { '.validate': "newData.isNumber()" }, '$other': { '.validate': 'false' } } }, { data: "type T {a: Number, b: String}", expect: { '.validate': "newData.hasChildren(['a', 'b'])", a: { '.validate': "newData.isNumber()" }, b: { '.validate': "newData.isString()" }, '$other': { '.validate': "false" } } }, { data: "type T {x: Number|Null}", expect: { '.validate': "newData.hasChildren()", x: { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } } }, { data: "type T {n: Number, validate() {return this.n < 7;}}", expect: { '.validate': "(newData.hasChildren(['n']) && newData.child('n').val() < 7)", n: { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } } }, { data: "type Bigger extends Number {validate() { return this > prior(this); }}" + "type T { ts: Bigger }", expect: { '.validate': "newData.hasChildren(['ts'])", ts: { '.validate': "(newData.isNumber() && newData.val() > data.val())" }, '$other': { '.validate': "false" } } }, { data: "type T {a: String, b: String, c: String}", expect: { '.validate': "newData.hasChildren(['a', 'b', 'c'])", a: { '.validate': "newData.isString()" }, b: { '.validate': "newData.isString()" }, c: { '.validate': "newData.isString()" }, '$other': { '.validate': "false" } } }, { data: "type B { foo: Number } type T extends B { bar: String }", expect: { '.validate': "newData.hasChildren(['foo', 'bar'])", foo: { '.validate': "newData.isNumber()" }, bar: { '.validate': "newData.isString()" }, '$other': { '.validate': "false" } } }, { data: "type T {n: Number, x: Map<String, Number>}", expect: { '.validate': "newData.hasChildren(['n'])", n: { '.validate': "newData.isNumber()" }, x: { '$key1': { '.validate': "newData.isNumber()" }, '.validate': "newData.hasChildren()" }, '$other': { '.validate': "false" } } }, { data: "type T {x: Map<String, Number>}", expect: { '.validate': "newData.hasChildren()", x: { '$key1': { '.validate': "newData.isNumber()" }, '.validate': "newData.hasChildren()" }, '$other': { '.validate': "false" } } }, { data: "type SmallString extends String { validate() { this.length < 32 } } " + "type T {x: Map<SmallString, Number>}", expect: { '.validate': "newData.hasChildren()", x: { '$key1': { '.validate': "($key1.length < 32 && newData.isNumber())" }, '.validate': "newData.hasChildren()" }, '$other': { '.validate': "false" } } }, { data: "type M extends Map<String, Number>; type T { x: M }", expect: { '.validate': "newData.hasChildren()", '$other': { '.validate': "false" }, 'x': { '$key1': { '.validate': "newData.isNumber()" }, '.validate': "newData.hasChildren()" } } }, { data: "type Pair<X, Y> { first: X, second: Y } type T extends Pair<String, Number>;", expect: { '.validate': "newData.hasChildren(['first', 'second'])", 'first': { '.validate': "newData.isString()" }, 'second': { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } } }, { data: "type X { a: Number, validate() { this.a == key() } } type T extends X[];", expect: { '$key1': { '.validate': "(newData.hasChildren(['a']) && newData.child('a').val() == $key1)", 'a': { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } }, '.validate': "newData.hasChildren()" } }, { data: "type X { a: Number, validate() { this.a == key() } } type T { x: X }", expect: { 'x': { '.validate': "(newData.hasChildren(['a']) && newData.child('a').val() == 'x')", 'a': { '.validate': "newData.isNumber()" }, '$other': { '.validate': "false" } }, '$other': { '.validate': "false" }, '.validate': "newData.hasChildren(['x'])" } }, { data: "type T extends String { validate() { root == 'new' && prior(root) == 'old' } }" + "path /t/x is Any { read() { root == 'old' } }", expect: { '.validate': "((newData.isString() && newData.parent().val() == 'new') && root.val() == 'old')", 'x': { '.read': "root.val() == 'old'" } } }, ]; helper.dataDrivenTest(tests, function (data, expect) { var symbols = parse(data + " path /t is T;"); var gen = new bolt.Generator(symbols); var rules = gen.generateRules(); if (expect === undefined) { assert.deepEqual(rules, { "rules": {} }); } else { assert.deepEqual(rules, { "rules": { t: expect } }); } }); }); suite("extendValidator", function () { var tests = [ { data: { target: {}, src: {} }, expect: {} }, { data: { target: {}, src: { '.x': [1] } }, expect: { '.x': [1] } }, { data: { target: { '.x': [1] }, src: { '.x': [2] } }, expect: { '.x': [1, 2] } }, { data: { target: { '.x': [1] }, src: { '.x': [2], c: { '.x': [3] } } }, expect: { '.x': [1, 2], c: { '.x': [3] } } }, { data: { target: { '.x': [1], c: { '.x': [2] } }, src: { c: { '.x': [3] } } }, expect: { '.x': [1], c: { '.x': [2, 3] } } }, { data: { target: {}, src: { a: { b: { c: { d: { '.x': [1], e: { '.x': [2] } } } } } } }, expect: { a: { b: { c: { d: { '.x': [1], e: { '.x': [2] } } } } } } }, ]; helper.dataDrivenTest(tests, function (data, expect) { generator.extendValidator(data.target, data.src); assert.deepEqual(data.target, expect); }); }); suite("mapValidator", function () { var tests = [ { data: { '.x': 'a' }, expect: { '.x': 'a+' } }, { data: { '.x': 'b' }, expect: {} }, ]; helper.dataDrivenTest(tests, function (data, expect) { generator.mapValidator(data, function (value, prop) { if (value === 'b') { return undefined; } return value + '+'; }); assert.deepEqual(data, expect); }); }); suite("Schema Generation Errors", function () { var tests = [ { data: "", expect: /at least one path/ }, { data: "type Simple extends String {a: String} path /x is Simple;", expect: /properties.*extend/ }, { data: "path /y { index() { return 1; }}", expect: /index.*string/i }, { data: "path /x { write() { return undefinedFunc(); }}", expect: /undefined.*function/i }, { data: "path /x is NoSuchType {}", expect: /No type.*NoSuchType/ }, { data: "path /x { unsupported() { true } }", warn: /unsupported method/i }, { data: "path /x { validate() { return this.test(123); } }", expect: /convert value/i }, { data: "path /x { validate() { return this.test('a/'); } }", expect: /convert value/i }, { data: "path /x { validate() { return this.test('/a/'); } }", expect: /convert value/i }, { data: "function f(a) { return f(a); } path / { validate() { return f(1); }}", expect: /recursive/i }, { data: "type X { $n: Number, $s: String } path / is X;", expect: /wild property/ }, { data: "type X { $$n: Number } path / is X;", expect: /property names/i }, { data: "type X { '\x01': Number } path / is X;", expect: /property names/i }, { data: "path / is Map;", expect: /No type.*non-generic/ }, { data: "type Pair<X, Y> {a: X, b: Y} path / is Pair;", expect: /No type.*non-generic/ }, { data: "path / is String<Number>;", expect: /No type.*generic/ }, { data: "path / is Map<Object, Number>;", expect: /must derive from String/ }, { data: "path / { write() { true } create() { true } }", expect: /write-aliasing.*create/i }, { data: "path / { write() { true } update() { true } }", expect: /write-aliasing.*update/i }, { data: "path / { write() { true } delete() { true } }", expect: /write-aliasing.*delete/i }, ]; helper.dataDrivenTest(tests, function (data, expect, t) { logger.reset(); logger.silent(); var symbols = parse(data); var gen = new bolt.Generator(symbols); var lastError; try { gen.generateRules(); } catch (e) { if (!expect) { throw e; } lastError = logger.getLastMessage() || e.message; assert.match(lastError, expect); return; } if (expect) { assert.fail(undefined, undefined, "No exception thrown."); } if (t.warn) { assert.match(logger.getLastMessage(), t.warn); } }); }); }); //# sourceMappingURL=data:application/json;charset=utf8;base64,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QUFFO1lBQzFCLEVBQUUsSUFBSSxFQUFFLEVBQUMsTUFBTSxFQUFFLEVBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxHQUFHLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFDLEVBQUM7Z0JBQzdELE1BQU0sRUFBRSxFQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFDLEVBQUU7WUFDMUMsRUFBRSxJQUFJLEVBQUUsRUFBQyxNQUFNLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFDLEVBQUUsR0FBRyxFQUFFLEVBQUMsQ0FBQyxFQUFFLEVBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBQyxFQUFDO2dCQUNsRSxNQUFNLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsRUFBQyxFQUFFO1lBQzFDLEVBQUUsSUFBSSxFQUFFLEVBQUMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFDLEVBQUMsRUFBQyxFQUFDLEVBQUMsRUFBQztnQkFDeEUsTUFBTSxFQUFFLEVBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxFQUFFLEVBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBQyxFQUFDLEVBQUMsRUFBQyxFQUFDLEVBQUU7U0FDNUQsQ0FBQztRQUVGLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLFVBQVMsSUFBSSxFQUFFLE1BQU07WUFDaEQsU0FBUyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNqRCxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDeEMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILEtBQUssQ0FBQyxjQUFjLEVBQUU7UUFDcEIsSUFBSSxLQUFLLEdBQUc7WUFDVixFQUFFLElBQUksRUFBRSxFQUFDLElBQUksRUFBRSxHQUFHLEVBQUMsRUFBRSxNQUFNLEVBQUUsRUFBQyxJQUFJLEVBQUUsSUFBSSxFQUFDLEVBQUU7WUFDM0MsRUFBRSxJQUFJLEVBQUUsRUFBQyxJQUFJLEVBQUUsR0FBRyxFQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRTtTQUNsQyxDQUFDO1FBRUYsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsVUFBUyxJQUFJLEVBQUUsTUFBTTtZQUNoRCxTQUFTLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxVQUFTLEtBQUssRUFBRSxJQUFJO2dCQUMvQyxJQUFJLEtBQUssS0FBSyxHQUFHLEVBQUU7b0JBQ2pCLE9BQU8sU0FBUyxDQUFDO2lCQUNsQjtnQkFDRCxPQUFPLEtBQUssR0FBRyxHQUFHLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNqQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsS0FBSyxDQUFDLDBCQUEwQixFQUFFO1FBQ2hDLElBQUksS0FBSyxHQUFHO1lBQ1YsRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDUixNQUFNLEVBQUUsbUJBQW1CLEVBQUU7WUFDL0IsRUFBRSxJQUFJLEVBQUUsMkRBQTJEO2dCQUNqRSxNQUFNLEVBQUUsb0JBQW9CLEVBQUU7WUFDaEMsRUFBRSxJQUFJLEVBQUUsa0NBQWtDO2dCQUN4QyxNQUFNLEVBQUUsZ0JBQWdCLEVBQUU7WUFDNUIsRUFBRSxJQUFJLEVBQUUsZ0RBQWdEO2dCQUN0RCxNQUFNLEVBQUUsc0JBQXNCLEVBQUU7WUFDbEMsRUFBRSxJQUFJLEVBQUUsMEJBQTBCO2dCQUNoQyxNQUFNLEVBQUUscUJBQXFCLEVBQUU7WUFDakMsRUFBRSxJQUFJLEVBQUUsb0NBQW9DO2dCQUMxQyxJQUFJLEVBQUUscUJBQXFCLEVBQUU7WUFFL0IsRUFBRSxJQUFJLEVBQUUsbURBQW1EO2dCQUN6RCxNQUFNLEVBQUUsZ0JBQWdCLEVBQUU7WUFDNUIsRUFBRSxJQUFJLEVBQUUsb0RBQW9EO2dCQUMxRCxNQUFNLEVBQUUsZ0JBQWdCLEVBQUU7WUFDNUIsRUFBRSxJQUFJLEVBQUUscURBQXFEO2dCQUMzRCxNQUFNLEVBQUUsZ0JBQWdCLEVBQUU7WUFFNUIsRUFBRSxJQUFJLEVBQUUsc0VBQXNFO2dCQUM1RSxNQUFNLEVBQUUsWUFBWSxFQUFFO1lBQ3hCLEVBQUUsSUFBSSxFQUFFLGdEQUFnRDtnQkFDdEQsTUFBTSxFQUFFLGVBQWUsRUFBRTtZQUMzQixFQUFFLElBQUksRUFBRSxxQ0FBcUM7Z0JBQzNDLE1BQU0sRUFBRSxpQkFBaUIsRUFBRTtZQUM3QixFQUFFLElBQUksRUFBRSx3Q0FBd0M7Z0JBQzlDLE1BQU0sRUFBRSxpQkFBaUIsRUFBRTtZQUM3QixFQUFFLElBQUksRUFBRSxnQkFBZ0I7Z0JBQ3RCLE1BQU0sRUFBRSxzQkFBc0IsRUFBRTtZQUNsQyxFQUFFLElBQUksRUFBRSw4Q0FBOEM7Z0JBQ3BELE1BQU0sRUFBRSxzQkFBc0IsRUFBRTtZQUNsQyxFQUFFLElBQUksRUFBRSwyQkFBMkI7Z0JBQ2pDLE1BQU0sRUFBRSxrQkFBa0IsRUFBRTtZQUM5QixFQUFFLElBQUksRUFBRSxnQ0FBZ0M7Z0JBQ3RDLE1BQU0sRUFBRSx5QkFBeUIsRUFBRTtZQUNyQyxFQUFFLElBQUksRUFBRSwrQ0FBK0M7Z0JBQ3JELE1BQU0sRUFBRSx5QkFBeUIsRUFBRTtZQUNyQyxFQUFFLElBQUksRUFBRSwrQ0FBK0M7Z0JBQ3JELE1BQU0sRUFBRSx5QkFBeUIsRUFBRTtZQUNyQyxFQUFFLElBQUksRUFBRSwrQ0FBK0M7Z0JBQ3JELE1BQU0sRUFBRSx5QkFBeUIsRUFBRTtTQUN0QyxDQUFDO1FBRUYsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsVUFBUyxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDbkQsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMxQixJQUFJLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDdEMsSUFBSSxTQUFpQixDQUFDO1lBRXRCLElBQUk7Z0JBQ0YsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO2FBQ3JCO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1YsSUFBSSxDQUFDLE1BQU0sRUFBRTtvQkFDWCxNQUFNLENBQUMsQ0FBQztpQkFDVDtnQkFDRCxTQUFTLEdBQUcsTUFBTSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUM7Z0JBQ2pELE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNoQyxPQUFPO2FBQ1I7WUFDRCxJQUFJLE1BQU0sRUFBRTtnQkFDVixNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsc0JBQXNCLENBQUMsQ0FBQzthQUMzRDtZQUNELElBQUksQ0FBQyxDQUFDLElBQUksRUFBRTtnQkFDVixNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDL0M7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJmaWxlIjoidGVzdC9nZW5lcmF0b3ItdGVzdC5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAxNSBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuaW1wb3J0ICogYXMgYm9sdCBmcm9tICcuLi9ib2x0JztcbmxldCBwYXJzZSA9IGJvbHQucGFyc2U7XG5pbXBvcnQgKiBhcyBnZW5lcmF0b3IgZnJvbSAnLi4vcnVsZXMtZ2VuZXJhdG9yJztcbmltcG9ydCAqIGFzIGFzdCBmcm9tICcuLi9hc3QnO1xuaW1wb3J0ICogYXMgZmlsZWlvIGZyb20gJy4uL2ZpbGUtaW8nO1xuaW1wb3J0ICogYXMgbG9nZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgKiBhcyBoZWxwZXIgZnJvbSAnLi90ZXN0LWhlbHBlcic7XG5pbXBvcnQge3NhbXBsZXN9IGZyb20gJy4vc2FtcGxlLWZpbGVzJztcblxuaW1wb3J0ICogYXMgY2hhaSBmcm9tICdjaGFpJztcbmNoYWkuY29uZmlnLnRydW5jYXRlVGhyZXNob2xkID0gMTAwMDtcbmxldCBhc3NlcnQgPSBjaGFpLmFzc2VydDtcblxuLy8gVE9ETzogVGVzdCBkdXBsaWNhdGVkIGZ1bmN0aW9uLCBhbmQgc2NoZW1hIGRlZmluaXRpb25zLlxuLy8gVE9ETzogVGVzdCBvdGhlciBwYXJzZXIgZXJyb3JzIC0gYXBwcm9wcmlhdGUgbWVzc2FnZXMgKGV4Y2VwdGlvbnMpLlxuXG5zdWl0ZShcIlJ1bGVzIEdlbmVyYXRvciBUZXN0c1wiLCBmdW5jdGlvbigpIHtcbiAgc3VpdGUoXCJCYXNpYyBTYW1wbGVzXCIsIGZ1bmN0aW9uKCkge1xuICAgIHZhciB0ZXN0cyA9IFtcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8ge3JlYWQoKSB7IHRydWUgfSB3cml0ZSgpIHsgdHJ1ZSB9fVwiLFxuICAgICAgICBleHBlY3Q6IHsgcnVsZXM6IHtcIi5yZWFkXCI6IFwidHJ1ZVwiLCBcIi53cml0ZVwiOiBcInRydWVcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8geyB3cml0ZSgpIHsgdHJ1ZSB9fVwiLFxuICAgICAgICBleHBlY3Q6IHsgcnVsZXM6IHtcIi53cml0ZVwiOiBcInRydWVcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8geyBjcmVhdGUoKSB7IHRydWUgfX1cIixcbiAgICAgICAgZXhwZWN0OiB7IHJ1bGVzOiB7XCIud3JpdGVcIjogXCJkYXRhLnZhbCgpID09IG51bGxcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8geyB1cGRhdGUoKSB7IHRydWUgfX1cIixcbiAgICAgICAgZXhwZWN0OiB7IHJ1bGVzOiB7XCIud3JpdGVcIjogXCIoZGF0YS52YWwoKSAhPSBudWxsICYmIG5ld0RhdGEudmFsKCkgIT0gbnVsbClcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8geyBkZWxldGUoKSB7IHRydWUgfX1cIixcbiAgICAgICAgZXhwZWN0OiB7IHJ1bGVzOiB7XCIud3JpdGVcIjogXCIoZGF0YS52YWwoKSAhPSBudWxsICYmIG5ld0RhdGEudmFsKCkgPT0gbnVsbClcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8ge3JlYWQoKSB7IHRydWUgfX1cIixcbiAgICAgICAgZXhwZWN0OiB7IHJ1bGVzOiB7XCIucmVhZFwiOiBcInRydWVcIn0gfVxuICAgICAgfSxcbiAgICAgIHsgZGF0YTogXCJwYXRoIC8geyByZWFkKCkgeyBmYWxzZSB9fVwiLFxuICAgICAgICBleHBlY3Q6IHsgcnVsZXM6IHt9IH1cbiAgICAgIH0sXG4gICAgICB7IGRhdGE6IFwicGF0aCAvIHtpbmRleCgpIHsgcmV0dXJuIFsnYScsICdiJ107IH19XCIsXG4gICAgICAgIGV4cGVjdDogeyBydWxlczoge1wiLmluZGV4T25cIjogW1wiYVwiLCBcImJcIl19IH1cbiAgICAgIH0sXG4gICAgICB7IGRhdGE6IFwicGF0aCAvIHsgdmFsaWRhdGUoKSB7IHJldHVybiB0aGlzID4gMDsgfX1cIixcbiAgICAgICAgZXhwZWN0OiB7IHJ1bGVzOiB7IFwiLnZhbGlkYXRlXCI6IFwibmV3RGF0YS52YWwoKSA+IDBcIiB9IH1cbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGhlbHBlci5kYXRhRHJpdmVuVGVzdCh0ZXN0cywgZnVuY3Rpb24oZGF0YSwgZXhwZWN0KSB7XG4gICAgICB2YXIgcmVzdWx0ID0gcGFyc2UoZGF0YSk7XG4gICAgICBhc3NlcnQub2socmVzdWx0KTtcbiAgICAgIHZhciBnZW4gPSBuZXcgYm9sdC5HZW5lcmF0b3IocmVzdWx0KTtcbiAgICAgIHZhciBqc29uID0gZ2VuLmdlbmVyYXRlUnVsZXMoKTtcbiAgICAgIGFzc2VydC5kZWVwRXF1YWwoanNvbiwgZXhwZWN0KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgc3VpdGUoXCJTYW1wbGUgZmlsZXNcIiwgZnVuY3Rpb24oKSB7XG4gICAgaGVscGVyLmRhdGFEcml2ZW5UZXN0KHNhbXBsZXMsIGZ1bmN0aW9uKGZpbGVuYW1lKSB7XG4gICAgICBmaWxlbmFtZSA9ICdzYW1wbGVzLycgKyBmaWxlbmFtZSArICcuJyArIGJvbHQuRklMRV9FWFRFTlNJT047XG4gICAgICByZXR1cm4gZmlsZWlvLnJlYWRGaWxlKGZpbGVuYW1lKVxuICAgICAgICAudGhlbihmdW5jdGlvbihyZXNwb25zZSkge1xuICAgICAgICAgIHZhciByZXN1bHQgPSBwYXJzZShyZXNwb25zZS5jb250ZW50KTtcbiAgICAgICAgICBhc3NlcnQub2socmVzdWx0LCByZXNwb25zZS51cmwpO1xuICAgICAgICAgIHZhciBnZW4gPSBuZXcgYm9sdC5HZW5lcmF0b3IocmVzdWx0KTtcbiAgICAgICAgICB2YXIganNvbiA9IGdlbi5nZW5lcmF0ZVJ1bGVzKCk7XG4gICAgICAgICAgYXNzZXJ0Lm9rKCdydWxlcycgaW4ganNvbiwgcmVzcG9uc2UudXJsICsgXCIgaGFzIHJ1bGVzXCIpO1xuICAgICAgICAgIHJldHVybiBmaWxlaW8ucmVhZEpTT05GaWxlKHJlc3BvbnNlLnVybC5yZXBsYWNlKCcuJyArIGJvbHQuRklMRV9FWFRFTlNJT04sICcuanNvbicpKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocmVzcG9uc2UyKSB7XG4gICAgICAgICAgICAgIGFzc2VydC5kZWVwRXF1YWwoanNvbiwgcmVzcG9uc2UyKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goZnVuY3Rpb24oZXJyb3IpIHtcbiAgICAgICAgICBhc3NlcnQub2soZmFsc2UsIGVycm9yLm1lc3NhZ2UpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgc3VpdGUoXCJQYXJ0aWFsIGV2YWx1YXRpb25cIiwgZnVuY3Rpb24oKSB7XG4gICAgdmFyIHRlc3RzID0gW1xuICAgICAgeyBmOiBcImZ1bmN0aW9uIGYoYSkgeyByZXR1cm4gdHJ1ZSA9PSBhOyB9XCIsIHg6IFwiZihhID09IGIpXCIsIGV4cGVjdDogXCJ0cnVlID09IChhID09IGIpXCIgfSxcbiAgICAgIHsgZjogXCJmdW5jdGlvbiBmKGEpIHsgcmV0dXJuIGEgPT0gdHJ1ZTsgfVwiLCB4OiBcImYoYSA9PSBiKVwiLCBleHBlY3Q6IFwiYSA9PSBiID09IHRydWVcIiB9LFxuICAgICAgeyBmOiBcImZ1bmN0aW9uIGYoYSkgeyByZXR1cm4gYSArIDM7IH1cIiwgeDogXCJmKDEgKyAyKVwiLCBleHBlY3Q6IFwiMSArIDIgKyAzXCIgfSxcbiAgICAgIHsgZjogXCJmdW5jdGlvbiBmKGEpIHsgcmV0dXJuIGEgKyAzOyB9XCIsIHg6IFwiZigxICogMilcIiwgZXhwZWN0OiBcIjEgKiAyICsgM1wiIH0sXG4gICAgICB7IGY6IFwiZnVuY3Rpb24gZihhKSB7IHJldHVybiBhICogMzsgfVwiLCB4OiBcImYoMSArIDIpXCIsIGV4cGVjdDogXCIoMSArIDIpICogM1wiIH0sXG4gICAgICB7IGY6IFwiZnVuY3Rpb24gZihhKSB7IHJldHVybiBhICsgMTsgfVwiLCB4OiBcImYoYSArIGEpXCIsIGV4cGVjdDogXCJhICsgYSArIDFcIiB9LFxuICAgICAgeyBmOiBcImZ1bmN0aW9uIGYoYSkgeyByZXR1cm4gZyhhKTsgfSBmdW5jdGlvbiBnKGEpIHsgcmV0dXJuIGEgPT0gdHJ1ZTsgfVwiLFxuICAgICAgICB4OiBcImYoMTIzKVwiLCBleHBlY3Q6IFwiMTIzID09IHRydWVcIiB9LFxuICAgICAgeyBmOiBcImZ1bmN0aW9uIGYoYSwgYikgeyByZXR1cm4gZyhhKSA9PSBnKGIpOyB9IGZ1bmN0aW9uIGcoYSkgeyByZXR1cm4gYSA9PSB0cnVlOyB9XCIsXG4gICAgICAgIHg6IFwiZigxLCAyKVwiLCBleHBlY3Q6IFwiMSA9PSB0cnVlID09ICgyID09IHRydWUpXCIgfSxcbiAgICAgIC8vIEhpZ2hsZXIgbGV2ZWwgZnVuY3Rpb24gd29ya3MgYXMgbG9uZyBhcyByZXR1cm5zIGEgY29uc3RhbnQgZnVuY3Rpb25cbiAgICAgIHsgZjogXCJmdW5jdGlvbiBmKCkgeyByZXR1cm4gZzsgfSBmdW5jdGlvbiBnKGEpIHsgcmV0dXJuIGEgPT0gdHJ1ZTsgfVwiLFxuICAgICAgICB4OiBcImYoKSgxMjMpXCIsIGV4cGVjdDogXCIxMjMgPT0gdHJ1ZVwiIH0sXG4gICAgICB7IGY6IFwiZnVuY3Rpb24gZihhKSB7IHJldHVybiBhICsgMTsgfVwiLCB4OiBcImFbZigxMjMpXVwiLCBleHBlY3Q6IFwiYVsxMjMgKyAxXVwiIH0sXG4gICAgICB7IGY6IFwiXCIsIHg6IFwidGhpc1wiLCBleHBlY3Q6IFwibmV3RGF0YS52YWwoKSA9PSB0cnVlXCIgfSxcbiAgICAgIHsgZjogXCJcIiwgeDogXCIhdGhpc1wiLCBleHBlY3Q6IFwiIShuZXdEYXRhLnZhbCgpID09IHRydWUpXCIgfSxcbiAgICAgIHsgZjogXCJcIiwgeDogXCJ0aGlzLnByb3BcIiwgZXhwZWN0OiBcIm5ld0RhdGEuY2hpbGQoJ3Byb3AnKS52YWwoKSA9PSB0cnVlXCIgfSxcbiAgICAgIHsgZjogXCJcIiwgeDogXCIhdGhpcy5wcm9wXCIsIGV4cGVjdDogXCIhKG5ld0RhdGEuY2hpbGQoJ3Byb3AnKS52YWwoKSA9PSB0cnVlKVwiIH0sXG4gICAgICB7IGY6IFwiXCIsIHg6IFwidGhpcy5mb28ucGFyZW50KClcIiwgZXhwZWN0OiBcIm5ld0RhdGEuY2hpbGQoJ2ZvbycpLnBhcmVudCgpLnZhbCgpID09IHRydWVcIiB9LFxuICAgICAgeyBmOiBcIlwiLFxuICAgICAgICB4OiBcInRoaXMuZm9vIHx8IHRoaXMuYmFyXCIsXG4gICAgICAgIGV4cGVjdDogXCIobmV3RGF0YS5jaGlsZCgnZm9vJykudmFsKCkgPT0gdHJ1ZSB8fCBuZXdEYXRhLmNoaWxkKCdiYXInKS52YWwoKSA9PSB0cnVlKVwifSxcbiAgICAgIC8vIFRPRE86IERvbid0IHN1cHBvcnQgc25hcHNob3QgZnVuY3Rpb25zIGJleW9uZCBwYXJlbnQuXG4gICAgICAvLyBUT0RPOiBTaG91bGQgd2FybiB1c2VyIG5vdCB0byB1c2UgRmlyZWJhc2UgYnVpbHRpbnMhXG4gICAgICAvLyB7IGY6IFwiXCIsIHg6IFwidGhpcy5pc1N0cmluZygpXCIsIGV4cGVjdDogXCJuZXdEYXRhLmNoaWxkKCdpc1N0cmluZycpLnZhbCgpID09IHRydWVcIiB9LFxuICAgICAgeyBmOiBcImZ1bmN0aW9uIGYoYSkgeyByZXR1cm4gYSA9PSAnMTIzJzsgfVwiLCB4OiBcImYodGhpcylcIiwgZXhwZWN0OiBcIm5ld0RhdGEudmFsKCkgPT0gJzEyMydcIiB9LFxuICAgICAgeyBmOiBcImZ1bmN0aW9uI