occam-verify-cli 0.0.1188 → 0.0.1190

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -145,17 +145,10 @@ export default domAssigned(class Subproof {
145
145
  const subproofNode = subproofNodeQuery(proofStepSubproofNode);
146
146
 
147
147
  if (subproofNode !== null) {
148
- const { Supposition, SubDerivation } = dom,
149
- subproofString = subproofStringFromSubproofNode(subproofNode, fileContext),
150
- suppositionNodes = suppositionNodesQuery(subproofNode),
151
- subDerivationNode = subDerivationNodeQuery(subproofNode),
148
+ const subproofString = subproofStringFromSubproofNode(subproofNode, fileContext),
152
149
  string = subproofString, ///
153
- suppositions = suppositionNodes.map((suppositionNode) => {
154
- const supposition = Supposition.fromSuppositionNode(suppositionNode, fileContext);
155
-
156
- return supposition;
157
- }),
158
- subDerivation = SubDerivation.fromSubDerivationNode(subDerivationNode, fileContext);
150
+ suppositions = suppositionsFromSubproofNode(subproofNode, fileContext),
151
+ subDerivation = subDerivationFromSubproofNode(subproofNode, fileContext);
159
152
 
160
153
  subproof = new Subproof(string, suppositions, subDerivation);
161
154
  }
@@ -163,3 +156,23 @@ export default domAssigned(class Subproof {
163
156
  return subproof;
164
157
  }
165
158
  });
159
+
160
+ function suppositionsFromSubproofNode(subproofNode, fileContext) {
161
+ const { Supposition } = dom,
162
+ suppositionNodes = suppositionNodesQuery(subproofNode),
163
+ suppositions = suppositionNodes.map((suppositionNode) => {
164
+ const supposition = Supposition.fromSuppositionNode(suppositionNode, fileContext);
165
+
166
+ return supposition;
167
+ });
168
+
169
+ return suppositions;
170
+ }
171
+
172
+ function subDerivationFromSubproofNode(subproofNode, fileContext) {
173
+ const { SubDerivation } = dom,
174
+ subDerivationNode = subDerivationNodeQuery(subproofNode),
175
+ subDerivation = SubDerivation.fromSubDerivationNode(subDerivationNode, fileContext);
176
+
177
+ return subDerivation;
178
+ }
package/src/dom/term.js CHANGED
@@ -14,9 +14,8 @@ import { typeFromJSON, typeToTypeJSON } from "../utilities/json";
14
14
 
15
15
  const { filter, compress } = arrayUtilities;
16
16
 
17
- const termNodeQuery = nodeQuery("/*/term[0]"),
18
- variableNodeQuery = nodeQuery("/term/variable!"),
19
- variableNodesQuery = nodesQuery("//variable");
17
+ const variableNodesQuery = nodesQuery("//variable"),
18
+ termVariableNodeQuery = nodeQuery("/*/term[0]/variable!");
20
19
 
21
20
  export default domAssigned(class Term {
22
21
  constructor(string, node, type) {
@@ -279,18 +278,14 @@ export default domAssigned(class Term {
279
278
  static fromDefinedAssertionNode(definedAssertionNode, context) {
280
279
  let term = null;
281
280
 
282
- const termNode = termNodeQuery(definedAssertionNode);
281
+ const termVariableNode = termVariableNodeQuery(definedAssertionNode);
283
282
 
284
- if (termNode !== null) {
285
- const variableNode = variableNodeQuery(termNode);
286
-
287
- if (variableNode !== null) {
288
- const node = termNode, ///
289
- string = context.nodeAsString(node),
290
- type = null;
283
+ if (termVariableNode !== null) {
284
+ const node = termVariableNode, ///
285
+ string = context.nodeAsString(node),
286
+ type = null;
291
287
 
292
- term = new Term(string, node, type);
293
- }
288
+ term = new Term(string, node, type);
294
289
  }
295
290
 
296
291
  return term;
@@ -299,18 +294,14 @@ export default domAssigned(class Term {
299
294
  static fromContainedAssertionNode(containedAssertionNode, context) {
300
295
  let term = null;
301
296
 
302
- const termNode = termNodeQuery(containedAssertionNode);
297
+ const termVariableNode = termVariableNodeQuery(containedAssertionNode);
303
298
 
304
- if (termNode !== null) {
305
- const variableNode = variableNodeQuery(termNode);
306
-
307
- if (variableNode !== null) {
308
- const node = termNode, ///
309
- string = context.nodeAsString(node),
310
- type = null;
299
+ if (termVariableNode !== null) {
300
+ const node = termVariableNode, ///
301
+ string = context.nodeAsString(node),
302
+ type = null;
311
303
 
312
- term = new Term(string, node, type);
313
- }
304
+ term = new Term(string, node, type);
314
305
  }
315
306
 
316
307
  return term;
@@ -289,24 +289,11 @@ export default class TopLevelAssertion {
289
289
  }
290
290
 
291
291
  static fromNode(Class, node, fileContext) {
292
- const { Label, Proof, Consequent, Supposition } = dom,
293
- proofNode = proofNodeQuery(node),
294
- labelNodes = labelNodesQuery(node),
295
- consequentNode = consequentNodeQuery(node),
296
- suppositionNodes = suppositionNodesQuery(node),
297
- labels = labelNodes.map((labelNode) => {
298
- const label = Label.fromLabelNode(labelNode, fileContext);
299
-
300
- return label;
301
- }),
292
+ const labels = labelsFromNode(node, fileContext),
302
293
  substitutions = Substitutions.fromNothing(),
303
- suppositions = suppositionNodes.map((suppositionNode) => {
304
- const supposition = Supposition.fromSuppositionNode(suppositionNode, fileContext);
305
-
306
- return supposition;
307
- }),
308
- consequent = Consequent.fromConsequentNode(consequentNode, fileContext),
309
- proof = Proof.fromProofNode(proofNode, fileContext),
294
+ suppositions = suppositionsFromNode(node, fileContext),
295
+ consequent = consequentFromNode(node, fileContext),
296
+ proof = proofFromNode(node, fileContext),
310
297
  string = stringFromLabels(labels),
311
298
  metaLemma = new Class(fileContext, string, labels, substitutions, suppositions, consequent, proof);
312
299
 
@@ -328,3 +315,43 @@ export function stringFromLabels(labels) {
328
315
  return string;
329
316
  }
330
317
 
318
+ function proofFromNode(node, fileContext) {
319
+ const { Proof } = dom,
320
+ proofNode = proofNodeQuery(node),
321
+ proof = Proof.fromProofNode(proofNode, fileContext);
322
+
323
+ return proof;
324
+ }
325
+
326
+ function labelsFromNode(node, fileContext) {
327
+ const { Label } = dom,
328
+ labelNodes = labelNodesQuery(node),
329
+ labels = labelNodes.map((labelNode) => {
330
+ const label = Label.fromLabelNode(labelNode, fileContext);
331
+
332
+ return label;
333
+ });
334
+
335
+ return labels;
336
+ }
337
+
338
+ function consequentFromNode(node, fileContext) {
339
+ const { Consequent } = dom,
340
+ consequentNode = consequentNodeQuery(node),
341
+ consequent = Consequent.fromConsequentNode(consequentNode, fileContext);
342
+
343
+ return consequent;
344
+ }
345
+
346
+ function suppositionsFromNode(node, fileContext) {
347
+ const { Supposition } = dom,
348
+ suppositionNodes = suppositionNodesQuery(node),
349
+ suppositions = suppositionNodes.map((suppositionNode) => {
350
+ const supposition = Supposition.fromSuppositionNode(suppositionNode, fileContext);
351
+
352
+ return supposition;
353
+ });
354
+
355
+ return suppositions;
356
+ }
357
+
package/src/dom/type.js CHANGED
@@ -178,12 +178,8 @@ class Type {
178
178
  }
179
179
 
180
180
  static fromTypeDeclarationNode(typeDeclarationNode, fileContext) {
181
- const typeDeclarationTypeNode = typeDeclarationTypeNodeQuery(typeDeclarationNode),
182
- typeDeclarationSuperTypeNode = typeDeclarationSuperTypeNodeQuery(typeDeclarationNode),
183
- typeNode = typeDeclarationTypeNode, ///
184
- superTypeNode = typeDeclarationSuperTypeNode, ///
185
- typeName = typeNameFromTypeNode(typeNode),
186
- superType = Type.fromTypeNode(superTypeNode),
181
+ const typeName = typeNameFromTypeDeclarationNode(typeDeclarationNode, fileContext),
182
+ superType = superTypeFromTypeDeclarationNode(typeDeclarationNode, fileContext),
187
183
  string = stringFromTypeNameAndSuperType(typeName, superType),
188
184
  name = typeName, ///
189
185
  type = new Type(string, name, superType);
@@ -222,6 +218,22 @@ function stringFromTypeNameAndSuperType(typeName, superType) {
222
218
  return string;
223
219
  }
224
220
 
221
+ function typeNameFromTypeDeclarationNode(typeDeclarationNode, fileContext) {
222
+ const typeDeclarationTypeNode = typeDeclarationTypeNodeQuery(typeDeclarationNode),
223
+ typeNode = typeDeclarationTypeNode, ///
224
+ typeName = typeNameFromTypeNode(typeNode);
225
+
226
+ return typeName;
227
+ }
228
+
229
+ function superTypeFromTypeDeclarationNode(typeDeclarationNode, fileContext) {
230
+ const typeDeclarationSuperTypeNode = typeDeclarationSuperTypeNodeQuery(typeDeclarationNode),
231
+ superTypeNode = typeDeclarationSuperTypeNode, ///
232
+ superType = Type.fromTypeNode(superTypeNode);
233
+
234
+ return superType;
235
+ }
236
+
225
237
  class ObjectType extends Type {
226
238
  toJSON() {
227
239
  const superType = null,
@@ -287,20 +287,26 @@ export default domAssigned(class Variable {
287
287
  }
288
288
 
289
289
  static fromVariableDeclarationNode(variableDeclarationNode, fileContext) {
290
- const { Type } = dom,
291
- variableDeclarationTypeNode = variableDeclarationTypeNodeQuery(variableDeclarationNode),
292
- variableDeclarationVariableNode = variableDeclarationVariableNodeQuery(variableDeclarationNode),
293
- typeNode = variableDeclarationTypeNode, ///
290
+ const variableDeclarationVariableNode = variableDeclarationVariableNodeQuery(variableDeclarationNode),
294
291
  variableNode = variableDeclarationVariableNode, ///
295
292
  variableName = variableNameFromVariableNode(variableNode),
296
- context = LocalContext.fromFileContext(fileContext),
297
293
  variableString = fileContext.nodeAsString(variableNode),
298
294
  string = variableString, ///
299
295
  node = variableNode, ///
300
296
  name = variableName, ///
301
- type = Type.fromTypeNode(typeNode, context),
297
+ type = typeFromVariableDeclarationNode(variableDeclarationNode, fileContext),
302
298
  variable = new Variable(string, node, name, type);
303
299
 
304
300
  return variable;
305
301
  }
306
302
  });
303
+
304
+ function typeFromVariableDeclarationNode(variableDeclarationNode, fileContext) {
305
+ const { Type } = dom,
306
+ variableDeclarationTypeNode = variableDeclarationTypeNodeQuery(variableDeclarationNode),
307
+ typeNode = variableDeclarationTypeNode, ///
308
+ context = LocalContext.fromFileContext(fileContext),
309
+ type = Type.fromTypeNode(typeNode, context);
310
+
311
+ return type;
312
+ }
@@ -1,246 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
8
- return _default;
9
- }
10
- });
11
- var _dom = /*#__PURE__*/ _interop_require_wildcard(require("../dom"));
12
- var _unify = /*#__PURE__*/ _interop_require_default(require("../mixins/proofStep/unify"));
13
- var _substitutions = /*#__PURE__*/ _interop_require_default(require("../substitutions"));
14
- var _assignments = require("../utilities/assignments");
15
- function _class_call_check(instance, Constructor) {
16
- if (!(instance instanceof Constructor)) {
17
- throw new TypeError("Cannot call a class as a function");
18
- }
19
- }
20
- function _defineProperties(target, props) {
21
- for(var i = 0; i < props.length; i++){
22
- var descriptor = props[i];
23
- descriptor.enumerable = descriptor.enumerable || false;
24
- descriptor.configurable = true;
25
- if ("value" in descriptor) descriptor.writable = true;
26
- Object.defineProperty(target, descriptor.key, descriptor);
27
- }
28
- }
29
- function _create_class(Constructor, protoProps, staticProps) {
30
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
31
- if (staticProps) _defineProperties(Constructor, staticProps);
32
- return Constructor;
33
- }
34
- function _define_property(obj, key, value) {
35
- if (key in obj) {
36
- Object.defineProperty(obj, key, {
37
- value: value,
38
- enumerable: true,
39
- configurable: true,
40
- writable: true
41
- });
42
- } else {
43
- obj[key] = value;
44
- }
45
- return obj;
46
- }
47
- function _interop_require_default(obj) {
48
- return obj && obj.__esModule ? obj : {
49
- default: obj
50
- };
51
- }
52
- function _getRequireWildcardCache(nodeInterop) {
53
- if (typeof WeakMap !== "function") return null;
54
- var cacheBabelInterop = new WeakMap();
55
- var cacheNodeInterop = new WeakMap();
56
- return (_getRequireWildcardCache = function(nodeInterop) {
57
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
58
- })(nodeInterop);
59
- }
60
- function _interop_require_wildcard(obj, nodeInterop) {
61
- if (!nodeInterop && obj && obj.__esModule) {
62
- return obj;
63
- }
64
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
65
- return {
66
- default: obj
67
- };
68
- }
69
- var cache = _getRequireWildcardCache(nodeInterop);
70
- if (cache && cache.has(obj)) {
71
- return cache.get(obj);
72
- }
73
- var newObj = {
74
- __proto__: null
75
- };
76
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
77
- for(var key in obj){
78
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
79
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
80
- if (desc && (desc.get || desc.set)) {
81
- Object.defineProperty(newObj, key, desc);
82
- } else {
83
- newObj[key] = obj[key];
84
- }
85
- }
86
- }
87
- newObj.default = obj;
88
- if (cache) {
89
- cache.set(obj, newObj);
90
- }
91
- return newObj;
92
- }
93
- var _ProofStep;
94
- var _default = (0, _dom.domAssigned)((_ProofStep = /*#__PURE__*/ function() {
95
- function ProofStep(string, subproof, statement, reference) {
96
- _class_call_check(this, ProofStep);
97
- this.string = string;
98
- this.subproof = subproof;
99
- this.statement = statement;
100
- this.reference = reference;
101
- }
102
- _create_class(ProofStep, [
103
- {
104
- key: "getString",
105
- value: function getString() {
106
- return this.string;
107
- }
108
- },
109
- {
110
- key: "getSubproof",
111
- value: function getSubproof() {
112
- return this.subproof;
113
- }
114
- },
115
- {
116
- key: "getStatement",
117
- value: function getStatement() {
118
- return this.statement;
119
- }
120
- },
121
- {
122
- key: "getReference",
123
- value: function getReference() {
124
- return this.reference;
125
- }
126
- },
127
- {
128
- key: "isQualified",
129
- value: function isQualified() {
130
- var qualified = this.reference !== null;
131
- return qualified;
132
- }
133
- },
134
- {
135
- key: "unify",
136
- value: function unify(substitutions, context) {
137
- var _this = this;
138
- var unified;
139
- if (this.subproof !== null) {
140
- unified = true; ///
141
- }
142
- if (this.statement !== null) {
143
- var proofStepString = this.string; ///
144
- context.trace("Unifying the '".concat(proofStepString, "' proof step..."));
145
- unified = _unify.default.some(function(unifyMixin) {
146
- var unified = unifyMixin(_this.statement, _this.reference, substitutions, context);
147
- if (unified) {
148
- return true;
149
- }
150
- });
151
- if (unified) {
152
- context.debug("...unified the '".concat(proofStepString, "' proof step."));
153
- }
154
- }
155
- return unified;
156
- }
157
- },
158
- {
159
- key: "unifyStatement",
160
- value: function unifyStatement(statement, context) {
161
- var statementUnified;
162
- var specificContext = context, generalContext = context, substitutions = _substitutions.default.fromNothing();
163
- if (this.subproof !== null) {
164
- var subproofUnified = statement.unifySubproof(this.subproof, substitutions, generalContext, specificContext);
165
- statementUnified = subproofUnified; ///
166
- }
167
- if (this.statement !== null) {
168
- statementUnified = statement.unifyStatement(this.statement, substitutions, generalContext, specificContext);
169
- }
170
- if (statementUnified) {
171
- var equivalences = context.getEquivalences(), substitutionsUnified = equivalences.unifySubstitutions(substitutions);
172
- statementUnified = substitutionsUnified; ///
173
- }
174
- return statementUnified;
175
- }
176
- },
177
- {
178
- key: "verifyAndUnify",
179
- value: function verifyAndUnify(substitutions, context) {
180
- var verifiedAndUnified = false;
181
- var assignments = [], verified = this.verify(substitutions, assignments, context);
182
- if (verified) {
183
- var unified = this.unify(substitutions, context);
184
- if (unified) {
185
- var assignmentsAssigned = (0, _assignments.assignAssignments)(assignments, context);
186
- if (assignmentsAssigned) {
187
- var proofStep = this; ///
188
- context.addProofStep(proofStep);
189
- verifiedAndUnified = true; ///
190
- }
191
- }
192
- }
193
- return verifiedAndUnified;
194
- }
195
- },
196
- {
197
- key: "verify",
198
- value: function verify(substitutions, assignments, context) {
199
- var verified = false;
200
- if (false) {
201
- ///
202
- } else if (this.subproof !== null) {
203
- var subproofVerified = this.subproof.verify(substitutions, context);
204
- verified = subproofVerified; ///
205
- } else if (this.statement !== null) {
206
- var proofStepString = this.string; ///
207
- context.trace("Verifying the '".concat(proofStepString, "' proof step..."));
208
- var qualified = this.isQualified(), stated = qualified, statementVerified = this.statement.verify(assignments, stated, context);
209
- if (statementVerified) {
210
- if (this.reference === null) {
211
- verified = true;
212
- } else {
213
- var referenceVerified = this.reference.verify(context);
214
- verified = referenceVerified; ///
215
- }
216
- }
217
- if (verified) {
218
- context.debug("...verified the '".concat(proofStepString, "' proof step."));
219
- }
220
- } else {
221
- var proofStepString1 = this.string;
222
- context.debug("Cannot verify the '".concat(proofStepString1, "' proof step because it is nonsense."));
223
- }
224
- return verified;
225
- }
226
- }
227
- ], [
228
- {
229
- key: "fromStatement",
230
- value: function fromStatement(statement, context) {
231
- var statementString = statement.getString(), string = statementString, subproof = null, reference = null, proofStep = new ProofStep(string, subproof, statement, reference);
232
- return proofStep;
233
- }
234
- },
235
- {
236
- key: "fromProofStepNode",
237
- value: function fromProofStepNode(proofStepNode, fileContext) {
238
- var Subproof = _dom.default.Subproof, Statement = _dom.default.Statement, Reference = _dom.default.Reference, node = proofStepNode, string = fileContext.nodeAsString(node), subproof = Subproof.fromProofStepNode(proofStepNode, fileContext), statement = Statement.fromProofStepNode(proofStepNode, fileContext), reference = Reference.fromProofStepNode(proofStepNode, fileContext), proofStep = new ProofStep(string, subproof, statement, reference);
239
- return proofStep;
240
- }
241
- }
242
- ]);
243
- return ProofStep;
244
- }(), _define_property(_ProofStep, "name", "ProofStep"), _ProofStep));
245
-
246
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kb20vcHJvb2ZTdGVwLm9sZC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcInVzZSBzdHJpY3RcIjtcblxuaW1wb3J0IGRvbSBmcm9tIFwiLi4vZG9tXCI7XG5pbXBvcnQgdW5pZnlNaXhpbnMgZnJvbSBcIi4uL21peGlucy9wcm9vZlN0ZXAvdW5pZnlcIjtcbmltcG9ydCBTdWJzdGl0dXRpb25zIGZyb20gXCIuLi9zdWJzdGl0dXRpb25zXCI7XG5cbmltcG9ydCB7IGRvbUFzc2lnbmVkIH0gZnJvbSBcIi4uL2RvbVwiO1xuaW1wb3J0IHsgYXNzaWduQXNzaWdubWVudHMgfSBmcm9tIFwiLi4vdXRpbGl0aWVzL2Fzc2lnbm1lbnRzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGRvbUFzc2lnbmVkKGNsYXNzIFByb29mU3RlcCB7XG4gIGNvbnN0cnVjdG9yKHN0cmluZywgc3VicHJvb2YsIHN0YXRlbWVudCwgcmVmZXJlbmNlKSB7XG4gICAgdGhpcy5zdHJpbmcgPSBzdHJpbmc7XG4gICAgdGhpcy5zdWJwcm9vZiA9IHN1YnByb29mO1xuICAgIHRoaXMuc3RhdGVtZW50ID0gc3RhdGVtZW50O1xuICAgIHRoaXMucmVmZXJlbmNlID0gcmVmZXJlbmNlO1xuICB9XG5cbiAgZ2V0U3RyaW5nKCkge1xuICAgIHJldHVybiB0aGlzLnN0cmluZztcbiAgfVxuXG4gIGdldFN1YnByb29mKCkge1xuICAgIHJldHVybiB0aGlzLnN1YnByb29mO1xuICB9XG5cbiAgZ2V0U3RhdGVtZW50KCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudDtcbiAgfVxuXG4gIGdldFJlZmVyZW5jZSgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWZlcmVuY2U7XG4gIH1cblxuICBpc1F1YWxpZmllZCgpIHtcbiAgICBjb25zdCBxdWFsaWZpZWQgPSAodGhpcy5yZWZlcmVuY2UgIT09IG51bGwpO1xuXG4gICAgcmV0dXJuIHF1YWxpZmllZDtcbiAgfVxuXG4gIHVuaWZ5KHN1YnN0aXR1dGlvbnMsIGNvbnRleHQpIHtcbiAgICBsZXQgdW5pZmllZDtcblxuICAgIGlmICh0aGlzLnN1YnByb29mICE9PSBudWxsKSB7XG4gICAgICB1bmlmaWVkID0gdHJ1ZTsgLy8vXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc3RhdGVtZW50ICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBwcm9vZlN0ZXBTdHJpbmcgPSB0aGlzLnN0cmluZzsgIC8vL1xuXG4gICAgICBjb250ZXh0LnRyYWNlKGBVbmlmeWluZyB0aGUgJyR7cHJvb2ZTdGVwU3RyaW5nfScgcHJvb2Ygc3RlcC4uLmApO1xuXG4gICAgICB1bmlmaWVkID0gdW5pZnlNaXhpbnMuc29tZSgodW5pZnlNaXhpbikgPT4ge1xuICAgICAgICBjb25zdCB1bmlmaWVkID0gdW5pZnlNaXhpbih0aGlzLnN0YXRlbWVudCwgdGhpcy5yZWZlcmVuY2UsIHN1YnN0aXR1dGlvbnMsIGNvbnRleHQpO1xuXG4gICAgICAgIGlmICh1bmlmaWVkKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAodW5pZmllZCkge1xuICAgICAgICBjb250ZXh0LmRlYnVnKGAuLi51bmlmaWVkIHRoZSAnJHtwcm9vZlN0ZXBTdHJpbmd9JyBwcm9vZiBzdGVwLmApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB1bmlmaWVkO1xuICB9XG5cbiAgdW5pZnlTdGF0ZW1lbnQoc3RhdGVtZW50LCBjb250ZXh0KSB7XG4gICAgbGV0IHN0YXRlbWVudFVuaWZpZWQ7XG5cbiAgICBjb25zdCBzcGVjaWZpY0NvbnRleHQgPSBjb250ZXh0LCAvLy9cbiAgICAgICAgICBnZW5lcmFsQ29udGV4dCA9IGNvbnRleHQsIC8vL1xuICAgICAgICAgIHN1YnN0aXR1dGlvbnMgPSBTdWJzdGl0dXRpb25zLmZyb21Ob3RoaW5nKCk7XG5cbiAgICBpZiAodGhpcy5zdWJwcm9vZiAhPT0gbnVsbCkge1xuICAgICAgY29uc3Qgc3VicHJvb2ZVbmlmaWVkID0gc3RhdGVtZW50LnVuaWZ5U3VicHJvb2YodGhpcy5zdWJwcm9vZiwgc3Vic3RpdHV0aW9ucywgZ2VuZXJhbENvbnRleHQsIHNwZWNpZmljQ29udGV4dCk7XG5cbiAgICAgIHN0YXRlbWVudFVuaWZpZWQgPSBzdWJwcm9vZlVuaWZpZWQ7IC8vL1xuICAgIH1cblxuICAgIGlmICh0aGlzLnN0YXRlbWVudCAhPT0gbnVsbCkge1xuICAgICAgc3RhdGVtZW50VW5pZmllZCA9IHN0YXRlbWVudC51bmlmeVN0YXRlbWVudCh0aGlzLnN0YXRlbWVudCwgc3Vic3RpdHV0aW9ucywgZ2VuZXJhbENvbnRleHQsIHNwZWNpZmljQ29udGV4dCk7XG4gICAgfVxuXG4gICAgaWYgKHN0YXRlbWVudFVuaWZpZWQpIHtcbiAgICAgIGNvbnN0IGVxdWl2YWxlbmNlcyA9IGNvbnRleHQuZ2V0RXF1aXZhbGVuY2VzKCksXG4gICAgICAgICAgICBzdWJzdGl0dXRpb25zVW5pZmllZCA9IGVxdWl2YWxlbmNlcy51bmlmeVN1YnN0aXR1dGlvbnMoc3Vic3RpdHV0aW9ucyk7XG5cbiAgICAgIHN0YXRlbWVudFVuaWZpZWQgPSBzdWJzdGl0dXRpb25zVW5pZmllZDsgIC8vL1xuICAgIH1cblxuICAgIHJldHVybiBzdGF0ZW1lbnRVbmlmaWVkO1xuICB9XG5cbiAgdmVyaWZ5QW5kVW5pZnkoc3Vic3RpdHV0aW9ucywgY29udGV4dCkge1xuICAgIGxldCB2ZXJpZmllZEFuZFVuaWZpZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0IGFzc2lnbm1lbnRzID0gW10sXG4gICAgICAgICAgdmVyaWZpZWQgPSB0aGlzLnZlcmlmeShzdWJzdGl0dXRpb25zLCBhc3NpZ25tZW50cywgY29udGV4dCk7XG5cbiAgICBpZiAodmVyaWZpZWQpIHtcbiAgICAgIGNvbnN0IHVuaWZpZWQgPSB0aGlzLnVuaWZ5KHN1YnN0aXR1dGlvbnMsIGNvbnRleHQpO1xuXG4gICAgICBpZiAodW5pZmllZCkge1xuICAgICAgICBjb25zdCBhc3NpZ25tZW50c0Fzc2lnbmVkID0gYXNzaWduQXNzaWdubWVudHMoYXNzaWdubWVudHMsIGNvbnRleHQpO1xuXG4gICAgICAgIGlmIChhc3NpZ25tZW50c0Fzc2lnbmVkKSB7XG4gICAgICAgICAgY29uc3QgcHJvb2ZTdGVwID0gdGhpczsgLy8vXG5cbiAgICAgICAgICBjb250ZXh0LmFkZFByb29mU3RlcChwcm9vZlN0ZXApO1xuXG4gICAgICAgICAgdmVyaWZpZWRBbmRVbmlmaWVkID0gdHJ1ZTsgLy8vXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdmVyaWZpZWRBbmRVbmlmaWVkO1xuICB9XG5cbiAgdmVyaWZ5KHN1YnN0aXR1dGlvbnMsIGFzc2lnbm1lbnRzLCBjb250ZXh0KSB7XG4gICAgbGV0IHZlcmlmaWVkID0gZmFsc2U7XG5cbiAgICBpZiAoZmFsc2UpIHtcbiAgICAgIC8vL1xuICAgIH0gZWxzZSBpZiAodGhpcy5zdWJwcm9vZiAhPT0gbnVsbCkge1xuICAgICAgY29uc3Qgc3VicHJvb2ZWZXJpZmllZCA9IHRoaXMuc3VicHJvb2YudmVyaWZ5KHN1YnN0aXR1dGlvbnMsIGNvbnRleHQpO1xuXG4gICAgICB2ZXJpZmllZCA9IHN1YnByb29mVmVyaWZpZWQ7ICAvLy9cbiAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGVtZW50ICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBwcm9vZlN0ZXBTdHJpbmcgPSB0aGlzLnN0cmluZzsgIC8vL1xuXG4gICAgICBjb250ZXh0LnRyYWNlKGBWZXJpZnlpbmcgdGhlICcke3Byb29mU3RlcFN0cmluZ30nIHByb29mIHN0ZXAuLi5gKTtcblxuICAgICAgY29uc3QgcXVhbGlmaWVkID0gdGhpcy5pc1F1YWxpZmllZCgpLFxuICAgICAgICAgICAgc3RhdGVkID0gcXVhbGlmaWVkLCAvLy9cbiAgICAgICAgICAgIHN0YXRlbWVudFZlcmlmaWVkID0gdGhpcy5zdGF0ZW1lbnQudmVyaWZ5KGFzc2lnbm1lbnRzLCBzdGF0ZWQsIGNvbnRleHQpO1xuXG4gICAgICBpZiAoc3RhdGVtZW50VmVyaWZpZWQpIHtcbiAgICAgICAgaWYgKHRoaXMucmVmZXJlbmNlID09PSBudWxsKSB7XG4gICAgICAgICAgdmVyaWZpZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IHJlZmVyZW5jZVZlcmlmaWVkID0gdGhpcy5yZWZlcmVuY2UudmVyaWZ5KGNvbnRleHQpO1xuXG4gICAgICAgICAgdmVyaWZpZWQgPSByZWZlcmVuY2VWZXJpZmllZDsgLy8vXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHZlcmlmaWVkKSB7XG4gICAgICAgIGNvbnRleHQuZGVidWcoYC4uLnZlcmlmaWVkIHRoZSAnJHtwcm9vZlN0ZXBTdHJpbmd9JyBwcm9vZiBzdGVwLmApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBwcm9vZlN0ZXBTdHJpbmcgPSB0aGlzLnN0cmluZztcblxuICAgICAgY29udGV4dC5kZWJ1ZyhgQ2Fubm90IHZlcmlmeSB0aGUgJyR7cHJvb2ZTdGVwU3RyaW5nfScgcHJvb2Ygc3RlcCBiZWNhdXNlIGl0IGlzIG5vbnNlbnNlLmApO1xuICAgIH1cblxuICAgIHJldHVybiB2ZXJpZmllZDtcbiAgfVxuXG4gIHN0YXRpYyBuYW1lID0gXCJQcm9vZlN0ZXBcIjtcblxuICBzdGF0aWMgZnJvbVN0YXRlbWVudChzdGF0ZW1lbnQsIGNvbnRleHQpIHtcbiAgICBjb25zdCBzdGF0ZW1lbnRTdHJpbmcgPSBzdGF0ZW1lbnQuZ2V0U3RyaW5nKCksXG4gICAgICAgICAgc3RyaW5nID0gc3RhdGVtZW50U3RyaW5nLCAvLy9cbiAgICAgICAgICBzdWJwcm9vZiA9IG51bGwsXG4gICAgICAgICAgcmVmZXJlbmNlID0gbnVsbCxcbiAgICAgICAgICBwcm9vZlN0ZXAgPSBuZXcgUHJvb2ZTdGVwKHN0cmluZywgc3VicHJvb2YsIHN0YXRlbWVudCwgcmVmZXJlbmNlKTtcblxuICAgIHJldHVybiBwcm9vZlN0ZXA7XG4gIH1cblxuICBzdGF0aWMgZnJvbVByb29mU3RlcE5vZGUocHJvb2ZTdGVwTm9kZSwgZmlsZUNvbnRleHQpIHtcbiAgICBjb25zdCB7IFN1YnByb29mLCBTdGF0ZW1lbnQsIFJlZmVyZW5jZSB9ID0gZG9tLFxuICAgICAgICAgIG5vZGUgPSBwcm9vZlN0ZXBOb2RlLCAvLy9cbiAgICAgICAgICBzdHJpbmcgPSBmaWxlQ29udGV4dC5ub2RlQXNTdHJpbmcobm9kZSksXG4gICAgICAgICAgc3VicHJvb2YgPSBTdWJwcm9vZi5mcm9tUHJvb2ZTdGVwTm9kZShwcm9vZlN0ZXBOb2RlLCBmaWxlQ29udGV4dCksXG4gICAgICAgICAgc3RhdGVtZW50ID0gU3RhdGVtZW50LmZyb21Qcm9vZlN0ZXBOb2RlKHByb29mU3RlcE5vZGUsIGZpbGVDb250ZXh0KSxcbiAgICAgICAgICByZWZlcmVuY2UgPSBSZWZlcmVuY2UuZnJvbVByb29mU3RlcE5vZGUocHJvb2ZTdGVwTm9kZSwgZmlsZUNvbnRleHQpLFxuICAgICAgICAgIHByb29mU3RlcCA9IG5ldyBQcm9vZlN0ZXAoc3RyaW5nLCBzdWJwcm9vZiwgc3RhdGVtZW50LCByZWZlcmVuY2UpO1xuXG4gICAgcmV0dXJuIHByb29mU3RlcDtcbiAgfVxufSk7XG4iXSwibmFtZXMiOlsiZG9tQXNzaWduZWQiLCJQcm9vZlN0ZXAiLCJzdHJpbmciLCJzdWJwcm9vZiIsInN0YXRlbWVudCIsInJlZmVyZW5jZSIsImdldFN0cmluZyIsImdldFN1YnByb29mIiwiZ2V0U3RhdGVtZW50IiwiZ2V0UmVmZXJlbmNlIiwiaXNRdWFsaWZpZWQiLCJxdWFsaWZpZWQiLCJ1bmlmeSIsInN1YnN0aXR1dGlvbnMiLCJjb250ZXh0IiwidW5pZmllZCIsInByb29mU3RlcFN0cmluZyIsInRyYWNlIiwidW5pZnlNaXhpbnMiLCJzb21lIiwidW5pZnlNaXhpbiIsImRlYnVnIiwidW5pZnlTdGF0ZW1lbnQiLCJzdGF0ZW1lbnRVbmlmaWVkIiwic3BlY2lmaWNDb250ZXh0IiwiZ2VuZXJhbENvbnRleHQiLCJTdWJzdGl0dXRpb25zIiwiZnJvbU5vdGhpbmciLCJzdWJwcm9vZlVuaWZpZWQiLCJ1bmlmeVN1YnByb29mIiwiZXF1aXZhbGVuY2VzIiwiZ2V0RXF1aXZhbGVuY2VzIiwic3Vic3RpdHV0aW9uc1VuaWZpZWQiLCJ1bmlmeVN1YnN0aXR1dGlvbnMiLCJ2ZXJpZnlBbmRVbmlmeSIsInZlcmlmaWVkQW5kVW5pZmllZCIsImFzc2lnbm1lbnRzIiwidmVyaWZpZWQiLCJ2ZXJpZnkiLCJhc3NpZ25tZW50c0Fzc2lnbmVkIiwiYXNzaWduQXNzaWdubWVudHMiLCJwcm9vZlN0ZXAiLCJhZGRQcm9vZlN0ZXAiLCJzdWJwcm9vZlZlcmlmaWVkIiwic3RhdGVkIiwic3RhdGVtZW50VmVyaWZpZWQiLCJyZWZlcmVuY2VWZXJpZmllZCIsImZyb21TdGF0ZW1lbnQiLCJzdGF0ZW1lbnRTdHJpbmciLCJmcm9tUHJvb2ZTdGVwTm9kZSIsInByb29mU3RlcE5vZGUiLCJmaWxlQ29udGV4dCIsIlN1YnByb29mIiwiZG9tIiwiU3RhdGVtZW50IiwiUmVmZXJlbmNlIiwibm9kZSIsIm5vZGVBc1N0cmluZyIsIm5hbWUiXSwibWFwcGluZ3MiOiJBQUFBOzs7OytCQVNBOzs7ZUFBQTs7OzJEQVBnQjs0REFDUTtvRUFDRTsyQkFHUTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7SUFFbEMsV0FBZUEsSUFBQUEsZ0JBQVcsOEJBQUM7YUFBTUMsVUFDbkJDLE1BQU0sRUFBRUMsUUFBUSxFQUFFQyxTQUFTLEVBQUVDLFNBQVM7Z0NBRG5CSjtRQUU3QixJQUFJLENBQUNDLE1BQU0sR0FBR0E7UUFDZCxJQUFJLENBQUNDLFFBQVEsR0FBR0E7UUFDaEIsSUFBSSxDQUFDQyxTQUFTLEdBQUdBO1FBQ2pCLElBQUksQ0FBQ0MsU0FBUyxHQUFHQTs7OztZQUduQkMsS0FBQUE7bUJBQUFBLFNBQUFBO2dCQUNFLE9BQU8sSUFBSSxDQUFDSixNQUFN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