manyfest 1.0.21 → 1.0.23
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.
- package/.babelrc +3 -0
- package/.browserslistrc +1 -1
- package/gulpfile-config.json +2 -2
- package/package.json +1 -2
- package/source/Manyfest-CleanWrapCharacters.js +1 -1
- package/source/Manyfest-ObjectAddress-DeleteValue.js +2 -63
- package/source/Manyfest-ObjectAddress-GetValue.js +54 -71
- package/source/Manyfest-ObjectAddress-SetValue.js +0 -1
- package/source/Manyfest-ParseConditionals.js +91 -0
- package/source/Manyfest.js +0 -2
- package/test/Manyfest_Embedded_Solvers_tests.js +24 -0
- package/test/Manyfest_Object_Read_tests.js +29 -1
- package/.config/installation/precedent.1.0.5.js +0 -339
package/.babelrc
ADDED
package/.browserslistrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
> 0.01%
|
package/gulpfile-config.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "manyfest",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"description": "JSON Object Manifest for Data Description and Parsing",
|
|
5
5
|
"main": "source/Manyfest.js",
|
|
6
6
|
"scripts": {
|
|
@@ -63,7 +63,6 @@
|
|
|
63
63
|
"vinyl-source-stream": "^2.0.0"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"precedent": "^1.0.11"
|
|
67
66
|
},
|
|
68
67
|
"author": "steven velozo <steven@velozo.com>",
|
|
69
68
|
"license": "MIT",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
//
|
|
14
14
|
// TODO: Should template literals be processed? If so what state do they have access to? That should happen here if so.
|
|
15
15
|
// TODO: Make a simple class include library with these
|
|
16
|
-
|
|
16
|
+
const cleanWrapCharacters = (pCharacter, pString) =>
|
|
17
17
|
{
|
|
18
18
|
if (pString.startsWith(pCharacter) && pString.endsWith(pCharacter))
|
|
19
19
|
{
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @author <steven@velozo.com>
|
|
3
3
|
*/
|
|
4
4
|
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
5
|
-
let libPrecedent = require('precedent');
|
|
6
5
|
let fCleanWrapCharacters = require('./Manyfest-CleanWrapCharacters.js');
|
|
6
|
+
let fParseConditionals = require(`../source/Manyfest-ParseConditionals.js`)
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Object Address Resolver - DeleteValue
|
|
@@ -34,73 +34,12 @@ class ManyfestObjectAddressResolverDeleteValue
|
|
|
34
34
|
this.logError = (typeof(pErrorLog) == 'function') ? pErrorLog : libSimpleLog;
|
|
35
35
|
|
|
36
36
|
this.cleanWrapCharacters = fCleanWrapCharacters;
|
|
37
|
-
this.precedent = new libPrecedent();
|
|
38
|
-
|
|
39
|
-
this.precedent.addPattern('<<~?', '?~>>',
|
|
40
|
-
(pMagicSearchExpression, pData) =>
|
|
41
|
-
{
|
|
42
|
-
if (typeof(pMagicSearchExpression) !== 'string')
|
|
43
|
-
{
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
// This expects a comma separated expression:
|
|
47
|
-
// Some.Address.In.The.Object,==,Search Term to Match
|
|
48
|
-
let tmpMagicComparisonPatternSet = pMagicSearchExpression.split(',');
|
|
49
|
-
|
|
50
|
-
let tmpSearchAddress = tmpMagicComparisonPatternSet[0];
|
|
51
|
-
let tmpSearchComparator = tmpMagicComparisonPatternSet[1];
|
|
52
|
-
let tmpSearchValue = tmpMagicComparisonPatternSet[2];
|
|
53
|
-
|
|
54
|
-
switch(tmpSearchComparator)
|
|
55
|
-
{
|
|
56
|
-
case '!=':
|
|
57
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) != tmpSearchValue);
|
|
58
|
-
break;
|
|
59
|
-
case '<':
|
|
60
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) < tmpSearchValue);
|
|
61
|
-
break;
|
|
62
|
-
case '>':
|
|
63
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) > tmpSearchValue);
|
|
64
|
-
break;
|
|
65
|
-
case '<=':
|
|
66
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) <= tmpSearchValue);
|
|
67
|
-
break;
|
|
68
|
-
case '>=':
|
|
69
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) >= tmpSearchValue);
|
|
70
|
-
break;
|
|
71
|
-
case '===':
|
|
72
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) == tmpSearchValue);
|
|
73
|
-
break;
|
|
74
|
-
case '==':
|
|
75
|
-
default:
|
|
76
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) == tmpSearchValue);
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
37
|
}
|
|
81
38
|
|
|
82
39
|
// TODO: Dry me
|
|
83
40
|
checkFilters(pAddress, pRecord)
|
|
84
41
|
{
|
|
85
|
-
|
|
86
|
-
// If we don't copy the string, precedent takes it out for good.
|
|
87
|
-
// TODO: Consider adding a "don't replace" option for precedent
|
|
88
|
-
let tmpAddress = pAddress;
|
|
89
|
-
|
|
90
|
-
// This allows the magic filtration with solver configuration
|
|
91
|
-
// TODO: We could pass more state in (e.g. parent address, object, etc.)
|
|
92
|
-
// TODO: Discuss this metaprogramming AT LENGTH
|
|
93
|
-
let tmpFilterState = (
|
|
94
|
-
{
|
|
95
|
-
Record: pRecord,
|
|
96
|
-
KeepRecord: true
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// This is about as complex as it gets.
|
|
100
|
-
|
|
101
|
-
this.precedent.parseString(tmpAddress, tmpFilterState);
|
|
102
|
-
|
|
103
|
-
return tmpFilterState.KeepRecord;
|
|
42
|
+
return fParseConditionals(this, pAddress, pRecord);
|
|
104
43
|
}
|
|
105
44
|
|
|
106
45
|
// Delete the value of an element at an address
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @author <steven@velozo.com>
|
|
3
3
|
*/
|
|
4
4
|
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
5
|
-
let libPrecedent = require('precedent');
|
|
6
5
|
let fCleanWrapCharacters = require('./Manyfest-CleanWrapCharacters.js');
|
|
6
|
+
let fParseConditionals = require(`../source/Manyfest-ParseConditionals.js`)
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Object Address Resolver - GetValue
|
|
@@ -34,77 +34,15 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
34
34
|
this.logError = (typeof(pErrorLog) == 'function') ? pErrorLog : libSimpleLog;
|
|
35
35
|
|
|
36
36
|
this.cleanWrapCharacters = fCleanWrapCharacters;
|
|
37
|
-
|
|
38
|
-
this.precedent = new libPrecedent();
|
|
39
|
-
|
|
40
|
-
this.precedent.addPattern('<<~?', '?~>>',
|
|
41
|
-
(pMagicSearchExpression, pData) =>
|
|
42
|
-
{
|
|
43
|
-
if (typeof(pMagicSearchExpression) !== 'string')
|
|
44
|
-
{
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
// This expects a comma separated expression:
|
|
48
|
-
// Some.Address.In.The.Object,==,Search Term to Match
|
|
49
|
-
let tmpMagicComparisonPatternSet = pMagicSearchExpression.split(',');
|
|
50
|
-
|
|
51
|
-
let tmpSearchAddress = tmpMagicComparisonPatternSet[0];
|
|
52
|
-
let tmpSearchComparator = tmpMagicComparisonPatternSet[1];
|
|
53
|
-
let tmpSearchValue = tmpMagicComparisonPatternSet[2];
|
|
54
|
-
|
|
55
|
-
switch(tmpSearchComparator)
|
|
56
|
-
{
|
|
57
|
-
case '!=':
|
|
58
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) != tmpSearchValue);
|
|
59
|
-
break;
|
|
60
|
-
case '<':
|
|
61
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) < tmpSearchValue);
|
|
62
|
-
break;
|
|
63
|
-
case '>':
|
|
64
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) > tmpSearchValue);
|
|
65
|
-
break;
|
|
66
|
-
case '<=':
|
|
67
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) <= tmpSearchValue);
|
|
68
|
-
break;
|
|
69
|
-
case '>=':
|
|
70
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) >= tmpSearchValue);
|
|
71
|
-
break;
|
|
72
|
-
case '===':
|
|
73
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) == tmpSearchValue);
|
|
74
|
-
break;
|
|
75
|
-
case '==':
|
|
76
|
-
default:
|
|
77
|
-
pData.KeepRecord = (this.getValueAtAddress(pData.Record, tmpSearchAddress) == tmpSearchValue);
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
37
|
}
|
|
82
38
|
|
|
83
39
|
checkFilters(pAddress, pRecord)
|
|
84
40
|
{
|
|
85
|
-
|
|
86
|
-
// If we don't copy the string, precedent takes it out for good.
|
|
87
|
-
// TODO: Consider adding a "don't replace" option for precedent
|
|
88
|
-
let tmpAddress = pAddress;
|
|
89
|
-
|
|
90
|
-
// This allows the magic filtration with configuration
|
|
91
|
-
// TODO: We could pass more state in (e.g. parent address, object, etc.)
|
|
92
|
-
// TODO: Discuss this metaprogramming AT LENGTH
|
|
93
|
-
let tmpFilterState = (
|
|
94
|
-
{
|
|
95
|
-
Record: pRecord,
|
|
96
|
-
KeepRecord: true
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// This is about as complex as it gets.
|
|
100
|
-
|
|
101
|
-
this.precedent.parseString(tmpAddress, tmpFilterState);
|
|
102
|
-
|
|
103
|
-
return tmpFilterState.KeepRecord;
|
|
41
|
+
return fParseConditionals(this, pAddress, pRecord);
|
|
104
42
|
}
|
|
105
43
|
|
|
106
44
|
// Get the value of an element at an address
|
|
107
|
-
getValueAtAddress (pObject, pAddress, pParentAddress)
|
|
45
|
+
getValueAtAddress (pObject, pAddress, pParentAddress, pRootObject)
|
|
108
46
|
{
|
|
109
47
|
// Make sure pObject (the object we are meant to be recursing) is an object (which could be an array or object)
|
|
110
48
|
if (typeof(pObject) != 'object') return undefined;
|
|
@@ -117,9 +55,54 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
117
55
|
tmpParentAddress = pParentAddress;
|
|
118
56
|
}
|
|
119
57
|
|
|
58
|
+
// Set the root object to the passed-in object if it isn't set yet. This is expected to be the root object.
|
|
59
|
+
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
60
|
+
|
|
120
61
|
// TODO: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
|
|
121
62
|
let tmpSeparatorIndex = pAddress.indexOf('.');
|
|
122
63
|
|
|
64
|
+
// Adding simple back-navigation in objects
|
|
65
|
+
if (tmpSeparatorIndex == 0)
|
|
66
|
+
{
|
|
67
|
+
// Given an address of "Bundle.Contract.IDContract...Project.IDProject" the ... would be interpreted as two back-navigations from IDContract.
|
|
68
|
+
// When the address is passed in, though, the first . is already eliminated. So we can count the dots.
|
|
69
|
+
let tmpParentAddressParts = tmpParentAddress.split('.');
|
|
70
|
+
|
|
71
|
+
let tmpBackNavigationCount = 0;
|
|
72
|
+
|
|
73
|
+
// Count the number of dots
|
|
74
|
+
for (let i = 0; i < pAddress.length; i++)
|
|
75
|
+
{
|
|
76
|
+
if (pAddress.charAt(i) != '.')
|
|
77
|
+
{
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
tmpBackNavigationCount++;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let tmpParentAddressLength = tmpParentAddressParts.length - tmpBackNavigationCount;
|
|
84
|
+
|
|
85
|
+
if (tmpParentAddressLength < 0)
|
|
86
|
+
{
|
|
87
|
+
// We are trying to back navigate more than we can.
|
|
88
|
+
// TODO: Should this be undefined or should we bank out at the bottom and try to go forward?
|
|
89
|
+
// This seems safest for now.
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
else
|
|
93
|
+
{
|
|
94
|
+
// We are trying to back navigate to a parent object.
|
|
95
|
+
// Recurse with the back-propagated parent address, and, the new address without the back-navigation dots.
|
|
96
|
+
let tmpRecurseAddress = pAddress.slice(tmpBackNavigationCount);
|
|
97
|
+
if (tmpParentAddressLength > 0)
|
|
98
|
+
{
|
|
99
|
+
tmpRecurseAddress = `${tmpParentAddressParts.slice(0, tmpParentAddressLength).join('.')}.${tmpRecurseAddress}`;
|
|
100
|
+
}
|
|
101
|
+
this.logInfo(`Back-navigation detected. Recursing back to address [${tmpRecurseAddress}]`);
|
|
102
|
+
return this.getValueAtAddress(tmpRootObject, tmpRecurseAddress);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
123
106
|
// This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
|
|
124
107
|
if (tmpSeparatorIndex == -1)
|
|
125
108
|
{
|
|
@@ -307,14 +290,14 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
307
290
|
// Continue to manage the parent address for recursion
|
|
308
291
|
tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
309
292
|
// Recurse directly into the subobject
|
|
310
|
-
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress, tmpParentAddress);
|
|
293
|
+
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
311
294
|
}
|
|
312
295
|
else
|
|
313
296
|
{
|
|
314
297
|
// Continue to manage the parent address for recursion
|
|
315
298
|
tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
316
299
|
// We parsed a valid number out of the boxed property name, so recurse into the array
|
|
317
|
-
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress, tmpParentAddress);
|
|
300
|
+
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
318
301
|
}
|
|
319
302
|
}
|
|
320
303
|
// The requirements to detect a boxed set element are:
|
|
@@ -342,7 +325,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
342
325
|
for (let i = 0; i < tmpArrayProperty.length; i++)
|
|
343
326
|
{
|
|
344
327
|
let tmpPropertyParentAddress = `${tmpParentAddress}[${i}]`;
|
|
345
|
-
let tmpValue = this.getValueAtAddress(pObject[tmpBoxedPropertyName][i], tmpNewAddress, tmpPropertyParentAddress);
|
|
328
|
+
let tmpValue = this.getValueAtAddress(pObject[tmpBoxedPropertyName][i], tmpNewAddress, tmpPropertyParentAddress, tmpRootObject);
|
|
346
329
|
|
|
347
330
|
tmpContainerObject[`${tmpPropertyParentAddress}.${tmpNewAddress}`] = tmpValue;
|
|
348
331
|
}
|
|
@@ -373,7 +356,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
373
356
|
for (let i = 0; i < tmpObjectPropertyKeys.length; i++)
|
|
374
357
|
{
|
|
375
358
|
let tmpPropertyParentAddress = `${tmpParentAddress}.${tmpObjectPropertyKeys[i]}`;
|
|
376
|
-
let tmpValue = this.getValueAtAddress(pObject[tmpObjectPropertyName][tmpObjectPropertyKeys[i]], tmpNewAddress, tmpPropertyParentAddress);
|
|
359
|
+
let tmpValue = this.getValueAtAddress(pObject[tmpObjectPropertyName][tmpObjectPropertyKeys[i]], tmpNewAddress, tmpPropertyParentAddress, tmpRootObject);
|
|
377
360
|
|
|
378
361
|
// The filtering is complex but allows config-based metaprogramming directly from schema
|
|
379
362
|
let tmpKeepRecord = this.checkFilters(pAddress, tmpValue);
|
|
@@ -397,7 +380,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
397
380
|
// If there is already a subobject pass that to the recursive thingy
|
|
398
381
|
// Continue to manage the parent address for recursion
|
|
399
382
|
tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
400
|
-
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, tmpParentAddress);
|
|
383
|
+
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
401
384
|
}
|
|
402
385
|
else
|
|
403
386
|
{
|
|
@@ -405,7 +388,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
405
388
|
// Continue to manage the parent address for recursion
|
|
406
389
|
tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
407
390
|
pObject[tmpSubObjectName] = {};
|
|
408
|
-
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, tmpParentAddress);
|
|
391
|
+
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
409
392
|
}
|
|
410
393
|
}
|
|
411
394
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Given a string, parse out any conditional expressions and set whether or not to keep the record.
|
|
2
|
+
//
|
|
3
|
+
// For instance:
|
|
4
|
+
// 'files[]<<~?format,==,Thumbnail?~>>'
|
|
5
|
+
// 'files[]<<~?format,==,Metadata?~>>'
|
|
6
|
+
// 'files[]<<~?size,>,4000?~>>'
|
|
7
|
+
//
|
|
8
|
+
// The wrapping parts are the <<~? and ?~>> megabrackets.
|
|
9
|
+
//
|
|
10
|
+
// The function does not need to alter the string -- just check the conditionals within.
|
|
11
|
+
|
|
12
|
+
// TODO: Consider making this an es6 class
|
|
13
|
+
|
|
14
|
+
// Let's use indexOf since it is apparently the fastest.
|
|
15
|
+
const _ConditionalStanzaStart = '<<~?';
|
|
16
|
+
const _ConditionalStanzaStartLength = _ConditionalStanzaStart.length;
|
|
17
|
+
const _ConditionalStanzaEnd = '?~>>';
|
|
18
|
+
const _ConditionalStanzaEndLength = _ConditionalStanzaEnd.length;
|
|
19
|
+
|
|
20
|
+
// Test the condition of a value in a record
|
|
21
|
+
const testCondition = (pManyfest, pRecord, pSearchAddress, pSearchComparator, pValue) =>
|
|
22
|
+
{
|
|
23
|
+
switch(pSearchComparator)
|
|
24
|
+
{
|
|
25
|
+
case '!=':
|
|
26
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) != pValue);
|
|
27
|
+
break;
|
|
28
|
+
case '<':
|
|
29
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) < pValue);
|
|
30
|
+
break;
|
|
31
|
+
case '>':
|
|
32
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) > pValue);
|
|
33
|
+
break;
|
|
34
|
+
case '<=':
|
|
35
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) <= pValue);
|
|
36
|
+
break;
|
|
37
|
+
case '>=':
|
|
38
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) >= pValue);
|
|
39
|
+
break;
|
|
40
|
+
case '===':
|
|
41
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) === pValue);
|
|
42
|
+
break;
|
|
43
|
+
case '==':
|
|
44
|
+
default:
|
|
45
|
+
return (pManyfest.getValueAtAddress(pRecord, pSearchAddress) == pValue);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const parseConditionals = (pManyfest, pAddress, pRecord) =>
|
|
51
|
+
{
|
|
52
|
+
let tmpKeepRecord = true;
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
Algorithm is simple:
|
|
56
|
+
|
|
57
|
+
1. Enuerate start points
|
|
58
|
+
|
|
59
|
+
2. Find stop points within each start point
|
|
60
|
+
3. Check the conditional
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
let tmpStartIndex = pAddress.indexOf(_ConditionalStanzaStart);
|
|
64
|
+
|
|
65
|
+
while (tmpStartIndex != -1)
|
|
66
|
+
{
|
|
67
|
+
let tmpStopIndex = pAddress.indexOf(_ConditionalStanzaEnd, tmpStartIndex+_ConditionalStanzaStartLength);
|
|
68
|
+
|
|
69
|
+
if (tmpStopIndex != -1)
|
|
70
|
+
{
|
|
71
|
+
let tmpMagicComparisonPatternSet = pAddress.substring(tmpStartIndex+_ConditionalStanzaStartLength, tmpStopIndex).split(',');
|
|
72
|
+
|
|
73
|
+
let tmpSearchAddress = tmpMagicComparisonPatternSet[0];
|
|
74
|
+
let tmpSearchComparator = tmpMagicComparisonPatternSet[1];
|
|
75
|
+
let tmpSearchValue = tmpMagicComparisonPatternSet[2];
|
|
76
|
+
|
|
77
|
+
// Process the piece
|
|
78
|
+
tmpKeepRecord = tmpKeepRecord && testCondition(pManyfest, pRecord, tmpSearchAddress, tmpSearchComparator, tmpSearchValue);
|
|
79
|
+
tmpStartIndex = pAddress.indexOf(_ConditionalStanzaStart, tmpStopIndex+_ConditionalStanzaEndLength);
|
|
80
|
+
}
|
|
81
|
+
else
|
|
82
|
+
{
|
|
83
|
+
tmpStartIndex = -1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return tmpKeepRecord;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = parseConditionals;
|
package/source/Manyfest.js
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
5
5
|
|
|
6
|
-
let libPrecedent = require('precedent');
|
|
7
|
-
|
|
8
6
|
let libHashTranslation = require('./Manyfest-HashTranslation.js');
|
|
9
7
|
let libObjectAddressCheckAddressExists = require('./Manyfest-ObjectAddress-CheckAddressExists.js');
|
|
10
8
|
let libObjectAddressGetValue = require('./Manyfest-ObjectAddress-GetValue.js');
|
|
@@ -25,6 +25,30 @@ suite
|
|
|
25
25
|
'Set Filtration',
|
|
26
26
|
()=>
|
|
27
27
|
{
|
|
28
|
+
test
|
|
29
|
+
(
|
|
30
|
+
'Underlying template processor should be able to filter records and be fast.',
|
|
31
|
+
(fTestComplete)=>
|
|
32
|
+
{
|
|
33
|
+
let _Manyfest = new libManyfest();
|
|
34
|
+
|
|
35
|
+
let templateParser = require(`../source/Manyfest-ParseConditionals.js`);
|
|
36
|
+
|
|
37
|
+
let tmpTestRecord = {Name:'Jimbo', Age:31, Pets:{Fido:'Dog',Spot:'Cat'}};
|
|
38
|
+
|
|
39
|
+
let tmpTestTemplate = 'Document.FormData.Parsable.Filters[]<<~?Name,==,Jimbo?~>>';
|
|
40
|
+
|
|
41
|
+
let tmpTestResult = templateParser(_Manyfest, tmpTestTemplate, tmpTestRecord);
|
|
42
|
+
|
|
43
|
+
Expect(tmpTestResult).to.equal(true);
|
|
44
|
+
|
|
45
|
+
tmpTestRecord.Name = 'Bob';
|
|
46
|
+
|
|
47
|
+
Expect(templateParser(_Manyfest, tmpTestTemplate, tmpTestRecord)).to.equal(false);
|
|
48
|
+
|
|
49
|
+
return fTestComplete();
|
|
50
|
+
}
|
|
51
|
+
)
|
|
28
52
|
test
|
|
29
53
|
(
|
|
30
54
|
'Magic filters should be magic.',
|
|
@@ -12,6 +12,7 @@ var Expect = Chai.expect;
|
|
|
12
12
|
let libManyfest = require('../source/Manyfest.js');
|
|
13
13
|
|
|
14
14
|
let _SampleDataArchiveOrgFrankenberry = require('./Data-Archive-org-Frankenberry.json');
|
|
15
|
+
let _SampleDataYahooWeather = require('./Data-Yahoo-Weather.json');
|
|
15
16
|
|
|
16
17
|
suite
|
|
17
18
|
(
|
|
@@ -100,9 +101,36 @@ suite
|
|
|
100
101
|
);
|
|
101
102
|
suite
|
|
102
103
|
(
|
|
103
|
-
'Advanced Read (with Arrays and Boxed Property addresses)',
|
|
104
|
+
'Advanced Read (with Arrays and Boxed Property and Backwards navigation addresses)',
|
|
104
105
|
()=>
|
|
105
106
|
{
|
|
107
|
+
test
|
|
108
|
+
(
|
|
109
|
+
'Access relative objects',
|
|
110
|
+
(fTestComplete)=>
|
|
111
|
+
{
|
|
112
|
+
let _Manyfest = new libManyfest();
|
|
113
|
+
// Traverse a relative address
|
|
114
|
+
let tmpVideoPointer = _Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'files[0]');
|
|
115
|
+
Expect(tmpVideoPointer.original).to.equal('frankerberry_countchockula_1971.0001.mpg');
|
|
116
|
+
// The .. means go back one level
|
|
117
|
+
let tmpDir = _Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'files[0]..dir');
|
|
118
|
+
Expect(tmpDir).to.equal("/7/items/FrankenberryCountChoculaTevevisionCommercial1971");
|
|
119
|
+
fTestComplete();
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
test
|
|
123
|
+
(
|
|
124
|
+
'Access relative objects complexly',
|
|
125
|
+
(fTestComplete)=>
|
|
126
|
+
{
|
|
127
|
+
let _Manyfest = new libManyfest();
|
|
128
|
+
Expect(_Manyfest.getValueAtAddress(_SampleDataYahooWeather, 'location.city')).to.equal('Sunnyvale');
|
|
129
|
+
// The .. means go back one level
|
|
130
|
+
Expect(_Manyfest.getValueAtAddress(_SampleDataYahooWeather, 'current_observation.wind...location.city')).to.equal('Sunnyvale');
|
|
131
|
+
fTestComplete();
|
|
132
|
+
}
|
|
133
|
+
);
|
|
106
134
|
test
|
|
107
135
|
(
|
|
108
136
|
'Access specific array elements',
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
5
|
-
|
|
6
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Precedent Meta-Templating
|
|
10
|
-
*
|
|
11
|
-
* @license MIT
|
|
12
|
-
*
|
|
13
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
14
|
-
*
|
|
15
|
-
* @description Process text streams, parsing out meta-template expressions.
|
|
16
|
-
*/
|
|
17
|
-
var libWordTree = require("./WordTree.js");
|
|
18
|
-
var libStringParser = require("./StringParser.js");
|
|
19
|
-
|
|
20
|
-
var Precedent = function () {
|
|
21
|
-
/**
|
|
22
|
-
* Precedent Constructor
|
|
23
|
-
*/
|
|
24
|
-
function Precedent() {
|
|
25
|
-
_classCallCheck(this, Precedent);
|
|
26
|
-
|
|
27
|
-
this.WordTree = new libWordTree();
|
|
28
|
-
|
|
29
|
-
this.StringParser = new libStringParser();
|
|
30
|
-
|
|
31
|
-
this.ParseTree = this.WordTree.ParseTree;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Add a Pattern to the Parse Tree
|
|
36
|
-
* @method addPattern
|
|
37
|
-
* @param {Object} pTree - A node on the parse tree to push the characters into
|
|
38
|
-
* @param {string} pPattern - The string to add to the tree
|
|
39
|
-
* @param {number} pIndex - callback function
|
|
40
|
-
* @return {bool} True if adding the pattern was successful
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
_createClass(Precedent, [{
|
|
45
|
-
key: "addPattern",
|
|
46
|
-
value: function addPattern(pPatternStart, pPatternEnd, pParser) {
|
|
47
|
-
return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Parse a string with the existing parse tree
|
|
52
|
-
* @method parseString
|
|
53
|
-
* @param {string} pString - The string to parse
|
|
54
|
-
* @return {string} The result from the parser
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
}, {
|
|
58
|
-
key: "parseString",
|
|
59
|
-
value: function parseString(pString) {
|
|
60
|
-
return this.StringParser.parseString(pString, this.ParseTree);
|
|
61
|
-
}
|
|
62
|
-
}]);
|
|
63
|
-
|
|
64
|
-
return Precedent;
|
|
65
|
-
}();
|
|
66
|
-
|
|
67
|
-
module.exports = Precedent;
|
|
68
|
-
|
|
69
|
-
},{"./StringParser.js":2,"./WordTree.js":3}],2:[function(require,module,exports){
|
|
70
|
-
'use strict';
|
|
71
|
-
|
|
72
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
73
|
-
|
|
74
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* String Parser
|
|
78
|
-
*
|
|
79
|
-
* @license MIT
|
|
80
|
-
*
|
|
81
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
82
|
-
*
|
|
83
|
-
* @description Parse a string, properly processing each matched token in the word tree.
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
var StringParser = function () {
|
|
87
|
-
/**
|
|
88
|
-
* StringParser Constructor
|
|
89
|
-
*/
|
|
90
|
-
function StringParser() {
|
|
91
|
-
_classCallCheck(this, StringParser);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Create a fresh parsing state object to work with.
|
|
96
|
-
* @method newParserState
|
|
97
|
-
* @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)
|
|
98
|
-
* @return {Object} A new parser state object for running a character parser on
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
_createClass(StringParser, [{
|
|
104
|
-
key: 'newParserState',
|
|
105
|
-
value: function newParserState(pParseTree) {
|
|
106
|
-
return {
|
|
107
|
-
ParseTree: pParseTree,
|
|
108
|
-
|
|
109
|
-
Output: '',
|
|
110
|
-
OutputBuffer: '',
|
|
111
|
-
|
|
112
|
-
Pattern: false,
|
|
113
|
-
|
|
114
|
-
PatternMatch: false,
|
|
115
|
-
PatternMatchOutputBuffer: ''
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Assign a node of the parser tree to be the next potential match.
|
|
121
|
-
* If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
|
|
122
|
-
* @method assignNode
|
|
123
|
-
* @param {Object} pNode - A node on the parse tree to assign
|
|
124
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
125
|
-
* @private
|
|
126
|
-
*/
|
|
127
|
-
|
|
128
|
-
}, {
|
|
129
|
-
key: 'assignNode',
|
|
130
|
-
value: function assignNode(pNode, pParserState) {
|
|
131
|
-
pParserState.PatternMatch = pNode;
|
|
132
|
-
|
|
133
|
-
// If the pattern has a END we can assume it has a parse function...
|
|
134
|
-
if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) {
|
|
135
|
-
// ... this is the legitimate start of a pattern.
|
|
136
|
-
pParserState.Pattern = pParserState.PatternMatch;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Append a character to the output buffer in the parser state.
|
|
142
|
-
* This output buffer is used when a potential match is being explored, or a match is being explored.
|
|
143
|
-
* @method appendOutputBuffer
|
|
144
|
-
* @param {string} pCharacter - The character to append
|
|
145
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
146
|
-
* @private
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
}, {
|
|
150
|
-
key: 'appendOutputBuffer',
|
|
151
|
-
value: function appendOutputBuffer(pCharacter, pParserState) {
|
|
152
|
-
pParserState.OutputBuffer += pCharacter;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Flush the output buffer to the output and clear it.
|
|
157
|
-
* @method flushOutputBuffer
|
|
158
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
159
|
-
* @private
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
|
-
}, {
|
|
163
|
-
key: 'flushOutputBuffer',
|
|
164
|
-
value: function flushOutputBuffer(pParserState) {
|
|
165
|
-
pParserState.Output += pParserState.OutputBuffer;
|
|
166
|
-
pParserState.OutputBuffer = '';
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
|
|
171
|
-
* @method checkPatternEnd
|
|
172
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
173
|
-
* @private
|
|
174
|
-
*/
|
|
175
|
-
|
|
176
|
-
}, {
|
|
177
|
-
key: 'checkPatternEnd',
|
|
178
|
-
value: function checkPatternEnd(pParserState) {
|
|
179
|
-
if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) {
|
|
180
|
-
// ... this is the end of a pattern, cut off the end tag and parse it.
|
|
181
|
-
// Trim the start and end tags off the output buffer now
|
|
182
|
-
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)));
|
|
183
|
-
// Flush the output buffer.
|
|
184
|
-
this.flushOutputBuffer(pParserState);
|
|
185
|
-
// End pattern mode
|
|
186
|
-
pParserState.Pattern = false;
|
|
187
|
-
pParserState.PatternMatch = false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Parse a character in the buffer.
|
|
193
|
-
* @method parseCharacter
|
|
194
|
-
* @param {string} pCharacter - The character to append
|
|
195
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
196
|
-
* @private
|
|
197
|
-
*/
|
|
198
|
-
|
|
199
|
-
}, {
|
|
200
|
-
key: 'parseCharacter',
|
|
201
|
-
value: function parseCharacter(pCharacter, pParserState) {
|
|
202
|
-
// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....
|
|
203
|
-
if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) {
|
|
204
|
-
// ... assign the node as the matched node.
|
|
205
|
-
this.assignNode(pParserState.ParseTree[pCharacter], pParserState);
|
|
206
|
-
this.appendOutputBuffer(pCharacter, pParserState);
|
|
207
|
-
}
|
|
208
|
-
// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)
|
|
209
|
-
else if (pParserState.PatternMatch) {
|
|
210
|
-
// If the pattern has a subpattern with this key
|
|
211
|
-
if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) {
|
|
212
|
-
// Continue matching patterns.
|
|
213
|
-
this.assignNode(pParserState.PatternMatch[pCharacter], pParserState);
|
|
214
|
-
}
|
|
215
|
-
this.appendOutputBuffer(pCharacter, pParserState);
|
|
216
|
-
if (pParserState.Pattern) {
|
|
217
|
-
// ... Check if this is the end of the pattern (if we are matching a valid pattern)...
|
|
218
|
-
this.checkPatternEnd(pParserState);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
|
|
222
|
-
else {
|
|
223
|
-
pParserState.Output += pCharacter;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Parse a string for matches, and process any template segments that occur.
|
|
229
|
-
* @method parseString
|
|
230
|
-
* @param {string} pString - The string to parse.
|
|
231
|
-
* @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
|
|
232
|
-
*/
|
|
233
|
-
|
|
234
|
-
}, {
|
|
235
|
-
key: 'parseString',
|
|
236
|
-
value: function parseString(pString, pParseTree) {
|
|
237
|
-
var tmpParserState = this.newParserState(pParseTree);
|
|
238
|
-
|
|
239
|
-
for (var i = 0; i < pString.length; i++) {
|
|
240
|
-
// TODO: This is not fast.
|
|
241
|
-
this.parseCharacter(pString[i], tmpParserState);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
this.flushOutputBuffer(tmpParserState);
|
|
245
|
-
|
|
246
|
-
return tmpParserState.Output;
|
|
247
|
-
}
|
|
248
|
-
}]);
|
|
249
|
-
|
|
250
|
-
return StringParser;
|
|
251
|
-
}();
|
|
252
|
-
|
|
253
|
-
module.exports = StringParser;
|
|
254
|
-
|
|
255
|
-
},{}],3:[function(require,module,exports){
|
|
256
|
-
'use strict';
|
|
257
|
-
|
|
258
|
-
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
259
|
-
|
|
260
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Word Tree
|
|
264
|
-
*
|
|
265
|
-
* @license MIT
|
|
266
|
-
*
|
|
267
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
268
|
-
*
|
|
269
|
-
* @description Create a tree (directed graph) of Javascript objects, one character per object.
|
|
270
|
-
*/
|
|
271
|
-
|
|
272
|
-
var WordTree = function () {
|
|
273
|
-
/**
|
|
274
|
-
* WordTree Constructor
|
|
275
|
-
*/
|
|
276
|
-
function WordTree() {
|
|
277
|
-
_classCallCheck(this, WordTree);
|
|
278
|
-
|
|
279
|
-
this.ParseTree = {};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Add a child character to a Parse Tree node
|
|
284
|
-
* @method addChild
|
|
285
|
-
* @param {Object} pTree - A parse tree to push the characters into
|
|
286
|
-
* @param {string} pPattern - The string to add to the tree
|
|
287
|
-
* @param {number} pIndex - callback function
|
|
288
|
-
* @returns {Object} The resulting leaf node that was added (or found)
|
|
289
|
-
* @private
|
|
290
|
-
*/
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
_createClass(WordTree, [{
|
|
294
|
-
key: 'addChild',
|
|
295
|
-
value: function addChild(pTree, pPattern, pIndex) {
|
|
296
|
-
if (pIndex > pPattern.length) return pTree;
|
|
297
|
-
|
|
298
|
-
if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {};
|
|
299
|
-
|
|
300
|
-
return pTree[pPattern[pIndex]];
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** Add a Pattern to the Parse Tree
|
|
304
|
-
* @method addPattern
|
|
305
|
-
* @param {Object} pTree - A node on the parse tree to push the characters into
|
|
306
|
-
* @param {string} pPattern - The string to add to the tree
|
|
307
|
-
* @param {number} pIndex - callback function
|
|
308
|
-
* @return {bool} True if adding the pattern was successful
|
|
309
|
-
*/
|
|
310
|
-
|
|
311
|
-
}, {
|
|
312
|
-
key: 'addPattern',
|
|
313
|
-
value: function addPattern(pPatternStart, pPatternEnd, pParser) {
|
|
314
|
-
if (pPatternStart.length < 1) return false;
|
|
315
|
-
|
|
316
|
-
var tmpLeaf = this.ParseTree;
|
|
317
|
-
|
|
318
|
-
// Add the tree of leaves iteratively
|
|
319
|
-
for (var i = 0; i < pPatternStart.length; i++) {
|
|
320
|
-
tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);
|
|
321
|
-
}tmpLeaf.PatternStart = pPatternStart;
|
|
322
|
-
tmpLeaf.PatternEnd = typeof pPatternEnd === 'string' && pPatternEnd.length > 0 ? pPatternEnd : pPatternStart;
|
|
323
|
-
tmpLeaf.Parse = typeof pParser === 'function' ? pParser : typeof pParser === 'string' ? function () {
|
|
324
|
-
return pParser;
|
|
325
|
-
} : function (pData) {
|
|
326
|
-
return pData;
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
}]);
|
|
332
|
-
|
|
333
|
-
return WordTree;
|
|
334
|
-
}();
|
|
335
|
-
|
|
336
|
-
module.exports = WordTree;
|
|
337
|
-
|
|
338
|
-
},{}]},{},[1])
|
|
339
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzb3VyY2UvUHJlY2VkZW50LmpzIiwic291cmNlL1N0cmluZ1BhcnNlci5qcyIsInNvdXJjZS9Xb3JkVHJlZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztBQ0FBOzs7Ozs7Ozs7QUFTQSxJQUFJLGNBQWMsd0JBQWxCO0FBQ0EsSUFBSSxrQkFBa0IsNEJBQXRCOztJQUVNLFM7QUFFTDs7O0FBR0Esc0JBQ0E7QUFBQTs7QUFDQyxPQUFLLFFBQUwsR0FBZ0IsSUFBSSxXQUFKLEVBQWhCOztBQUVBLE9BQUssWUFBTCxHQUFvQixJQUFJLGVBQUosRUFBcEI7O0FBRUEsT0FBSyxTQUFMLEdBQWlCLEtBQUssUUFBTCxDQUFjLFNBQS9CO0FBQ0E7O0FBRUQ7Ozs7Ozs7Ozs7Ozs2QkFRVyxhLEVBQWUsVyxFQUFhLE8sRUFDdkM7QUFDQyxVQUFPLEtBQUssUUFBTCxDQUFjLFVBQWQsQ0FBeUIsYUFBekIsRUFBd0MsV0FBeEMsRUFBcUQsT0FBckQsQ0FBUDtBQUNBOztBQUVEOzs7Ozs7Ozs7OEJBTVksTyxFQUNaO0FBQ0MsVUFBTyxLQUFLLFlBQUwsQ0FBa0IsV0FBbEIsQ0FBOEIsT0FBOUIsRUFBdUMsS0FBSyxTQUE1QyxDQUFQO0FBQ0E7Ozs7OztBQUdGLE9BQU8sT0FBUCxHQUFpQixTQUFqQjs7Ozs7Ozs7O0FDbkRBOzs7Ozs7Ozs7O0lBVU0sWTtBQUVMOzs7QUFHQSx5QkFDQTtBQUFBO0FBQ0M7O0FBRUQ7Ozs7Ozs7Ozs7O2lDQU9nQixVLEVBQ2hCO0FBQ0MsVUFDQTtBQUNJLGVBQVcsVUFEZjs7QUFHQyxZQUFRLEVBSFQ7QUFJQyxrQkFBYyxFQUpmOztBQU1DLGFBQVMsS0FOVjs7QUFRQyxrQkFBYyxLQVJmO0FBU0MsOEJBQTBCO0FBVDNCLElBREE7QUFZQTs7QUFFRDs7Ozs7Ozs7Ozs7NkJBUVksSyxFQUFPLFksRUFDbkI7QUFDQyxnQkFBYSxZQUFiLEdBQTRCLEtB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RUFBakI7QUFDQTs7QUFFRDs7Ozs7Ozs7Ozs7OzsyQkFTVSxLLEVBQU8sUSxFQUFVLE0sRUFDM0I7QUFDQyxPQUFJLFNBQVMsU0FBUyxNQUF0QixFQUNDLE9BQU8sS0FBUDs7QUFFRCxPQUFJLENBQUMsTUFBTSxjQUFOLENBQXFCLFNBQVMsTUFBVCxDQUFyQixDQUFMLEVBQ0MsTUFBTSxTQUFTLE1BQVQsQ0FBTixJQUEwQixFQUExQjs7QUFFRCxVQUFPLE1BQU0sU0FBUyxNQUFULENBQU4sQ0FBUDtBQUNBOztBQUVEOzs7Ozs7Ozs7OzZCQU9ZLGEsRUFBZSxXLEVBQWEsTyxFQUN4QztBQUNDLE9BQUksY0FBYyxNQUFkLEdBQXVCLENBQTNCLEVBQ0MsT0FBTyxLQUFQOztBQUVELE9BQUksVUFBVSxLQUFLLFNBQW5COztBQUVBO0FBQ0EsUUFBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLGNBQWMsTUFBbEMsRUFBMEMsR0FBMUM7QUFDQyxjQUFVLEtBQUssUUFBTCxDQUFjLE9BQWQsRUFBdUIsYUFBdkIsRUFBc0MsQ0FBdEMsQ0FBVjtBQURELElBR0EsUUFBUSxZQUFSLEdBQXVCLGFBQXZCO0FBQ0EsV0FBUSxVQUFSLEdBQXVCLE9BQU8sV0FBUCxLQUF3QixRQUF6QixJQUF1QyxZQUFZLE1BQVosR0FBcUIsQ0FBN0QsR0FBbUUsV0FBbkUsR0FBaUYsYUFBdEc7QUFDQSxXQUFRLEtBQVIsR0FBaUIsT0FBTyxPQUFQLEtBQW9CLFVBQXJCLEdBQW1DLE9BQW5DLEdBQ1gsT0FBTyxPQUFQLEtBQW9CLFFBQXJCLEdBQWlDLFlBQU07QUFBRSxXQUFPLE9BQVA7QUFBaUIsSUFBMUQsR0FDQSxVQUFDLEtBQUQsRUFBVztBQUFFLFdBQU8sS0FBUDtBQUFlLElBRmhDOztBQUlBLFVBQU8sSUFBUDtBQUNBOzs7Ozs7QUFHRixPQUFPLE9BQVAsR0FBaUIsUUFBakIiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyoqXG4qIFByZWNlZGVudCBNZXRhLVRlbXBsYXRpbmdcbipcbiogQGxpY2Vuc2UgICAgIE1JVFxuKlxuKiBAYXV0aG9yICAgICAgU3RldmVuIFZlbG96byA8c3RldmVuQHZlbG96by5jb20+XG4qXG4qIEBkZXNjcmlwdGlvbiBQcm9jZXNzIHRleHQgc3RyZWFtcywgcGFyc2luZyBvdXQgbWV0YS10ZW1wbGF0ZSBleHByZXNzaW9ucy5cbiovXG52YXIgbGliV29yZFRyZWUgPSByZXF1aXJlKGAuL1dvcmRUcmVlLmpzYCk7XG52YXIgbGliU3RyaW5nUGFyc2VyID0gcmVxdWlyZShgLi9TdHJpbmdQYXJzZXIuanNgKTtcblxuY2xhc3MgUHJlY2VkZW50XG57XG5cdC8qKlxuXHQgKiBQcmVjZWRlbnQgQ29uc3RydWN0b3Jcblx0ICovXG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHRcdHRoaXMuV29yZFRyZWUgPSBuZXcgbGliV29yZFRyZWUoKTtcblx0XHRcblx0XHR0aGlzLlN0cmluZ1BhcnNlciA9IG5ldyBsaWJTdHJpbmdQYXJzZXIoKTtcblxuXHRcdHRoaXMuUGFyc2VUcmVlID0gdGhpcy5Xb3JkVHJlZS5QYXJzZVRyZWU7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBBZGQgYSBQYXR0ZXJuIHRvIHRoZSBQYXJzZSBUcmVlXG5cdCAqIEBtZXRob2QgYWRkUGF0dGVyblxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFRyZWUgLSBBIG5vZGUgb24gdGhlIHBhcnNlIHRyZWUgdG8gcHVzaCB0aGUgY2hhcmFjdGVycyBpbnRvXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwUGF0dGVybiAtIFRoZSBzdHJpbmcgdG8gYWRkIHRvIHRoZSB0cmVlXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBwSW5kZXggLSBjYWxsYmFjayBmdW5jdGlvblxuXHQgKiBAcmV0dXJuIHtib29sfSBUcnVlIGlmIGFkZGluZyB0aGUgcGF0dGVybiB3YXMgc3VjY2Vzc2Z1bFxuXHQgKi9cblx0YWRkUGF0dGVybihwUGF0dGVyblN0YXJ0LCBwUGF0dGVybkVuZCwgcFBhcnNlcilcblx0e1xuXHRcdHJldHVybiB0aGlzLldvcmRUcmVlLmFkZFBhdHRlcm4ocFBhdHRlcm5TdGFydCwgcFBhdHRlcm5FbmQsIHBQYXJzZXIpO1xuXHR9XG5cdFxuXHQvKipcblx0ICogUGFyc2UgYSBzdHJpbmcgd2l0aCB0aGUgZXhpc3RpbmcgcGFyc2UgdHJlZVxuXHQgKiBAbWV0aG9kIHBhcnNlU3RyaW5nXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwU3RyaW5nIC0gVGhlIHN0cmluZyB0byBwYXJzZVxuXHQgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSByZXN1bHQgZnJvbSB0aGUgcGFyc2VyXG5cdCAqL1xuXHRwYXJzZVN0cmluZyhwU3RyaW5nKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuU3RyaW5nUGFyc2VyLnBhcnNlU3RyaW5nKHBTdHJpbmcsIHRoaXMuUGFyc2VUcmVlKTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFByZWNlZGVudDtcbiIsIi8qKlxuKiBTdHJpbmcgUGFyc2VyXG4qXG4qIEBsaWNlbnNlICAgICBNSVRcbipcbiogQGF1dGhvciAgICAgIFN0ZXZlbiBWZWxvem8gPHN0ZXZlbkB2ZWxvem8uY29tPlxuKlxuKiBAZGVzY3JpcHRpb24gUGFyc2UgYSBzdHJpbmcsIHByb3Blcmx5IHByb2Nlc3NpbmcgZWFjaCBtYXRjaGVkIHRva2VuIGluIHRoZSB3b3JkIHRyZWUuXG4qL1xuXG5jbGFzcyBTdHJpbmdQYXJzZXJcbntcblx0LyoqXG5cdCAqIFN0cmluZ1BhcnNlciBDb25zdHJ1Y3RvclxuXHQgKi9cblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBDcmVhdGUgYSBmcmVzaCBwYXJzaW5nIHN0YXRlIG9iamVjdCB0byB3b3JrIHdpdGguXG5cdCAqIEBtZXRob2QgbmV3UGFyc2VyU3RhdGVcblx0ICogQHBhcmFtIHtPYmplY3R9IHBQYXJzZVRyZWUgLSBBIG5vZGUgb24gdGhlIHBhcnNlIHRyZWUgdG8gYmVnaW4gcGFyc2luZyBmcm9tICh1c3VhbGx5IHJvb3QpXG5cdCAqIEByZXR1cm4ge09iamVjdH0gQSBuZXcgcGFyc2VyIHN0YXRlIG9iamVjdCBmb3IgcnVubmluZyBhIGNoYXJhY3RlciBwYXJzZXIgb25cblx0ICogQHByaXZhdGVcblx0ICovXG5cdG5ld1BhcnNlclN0YXRlIChwUGFyc2VUcmVlKVxuXHR7XG5cdFx0cmV0dXJuIChcblx0XHR7XG5cdFx0ICAgIFBhcnNlVHJlZTogcFBhcnNlVHJlZSxcblxuXHRcdFx0T3V0cHV0OiAnJyxcblx0XHRcdE91dHB1dEJ1ZmZlcjogJycsXG5cblx0XHRcdFBhdHRlcm46IGZhbHNlLFxuXG5cdFx0XHRQYXR0ZXJuTWF0Y2g6IGZhbHNlLFxuXHRcdFx0UGF0dGVybk1hdGNoT3V0cHV0QnVmZmVyOiAnJ1xuXHRcdH0pO1xuXHR9XG5cdFx0XG5cdC8qKlxuXHQgKiBBc3NpZ24gYSBub2RlIG9mIHRoZSBwYXJzZXIgdHJlZSB0byBiZSB0aGUgbmV4dCBwb3RlbnRpYWwgbWF0Y2guXG5cdCAqIElmIHRoZSBub2RlIGhhcyBhIFBhdHRlcm5FbmQgcHJvcGVydHksIGl0IGlzIGEgdmFsaWQgbWF0Y2ggYW5kIHN1cGVyY2VkZXMgdGhlIGxhc3QgdmFsaWQgbWF0Y2ggKG9yIGJlY29tZXMgdGhlIGluaXRpYWwgbWF0Y2gpLlxuXHQgKiBAbWV0aG9kIGFzc2lnbk5vZGVcblx0ICogQHBhcmFtIHtPYmplY3R9IHBOb2RlIC0gQSBub2RlIG9uIHRoZSBwYXJzZSB0cmVlIHRvIGFzc2lnblxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFBhcnNlclN0YXRlIC0gVGhlIHN0YXRlIG9iamVjdCBmb3IgdGhlIGN1cnJlbnQgcGFyc2luZyB0YXNrXG5cdCAqIEBwcml2YXRlXG5cdCAqL1xuXHRhc3NpZ25Ob2RlIChwTm9kZSwgcFBhcnNlclN0YXRlKVxuXHR7XG5cdFx0cFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaCA9IHBOb2RlO1xuXG5cdFx0Ly8gSWYgdGhlIHBhdHRlcm4gaGFzIGEgRU5EIHdlIGNhbiBhc3N1bWUgaXQgaGFzIGEgcGFyc2UgZnVuY3Rpb24uLi5cblx0XHRpZiAocFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaC5oYXNPd25Qcm9wZXJ0eSgnUGF0dGVybkVuZCcpKVxuXHRcdHtcblx0XHRcdC8vIC4uLiB0aGlzIGlzIHRoZSBsZWdpdGltYXRlIHN0YXJ0IG9mIGEgcGF0dGVybi5cblx0XHRcdHBQYXJzZXJTdGF0ZS5QYXR0ZXJuID0gcFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaDtcblx0XHR9XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBBcHBlbmQgYSBjaGFyYWN0ZXIgdG8gdGhlIG91dHB1dCBidWZmZXIgaW4gdGhlIHBhcnNlciBzdGF0ZS5cblx0ICogVGhpcyBvdXRwdXQgYnVmZmVyIGlzIHVzZWQgd2hlbiBhIHBvdGVudGlhbCBtYXRjaCBpcyBiZWluZyBleHBsb3JlZCwgb3IgYSBtYXRjaCBpcyBiZWluZyBleHBsb3JlZC5cblx0ICogQG1ldGhvZCBhcHBlbmRPdXRwdXRCdWZmZXJcblx0ICogQHBhcmFtIHtzdHJpbmd9IHBDaGFyYWN0ZXIgLSBUaGUgY2hhcmFjdGVyIHRvIGFwcGVuZFxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFBhcnNlclN0YXRlIC0gVGhlIHN0YXRlIG9iamVjdCBmb3IgdGhlIGN1cnJlbnQgcGFyc2luZyB0YXNrXG5cdCAqIEBwcml2YXRlXG5cdCAqL1xuXHRhcHBlbmRPdXRwdXRCdWZmZXIgKHBDaGFyYWN0ZXIsIHBQYXJzZXJTdGF0ZSlcblx0e1xuXHRcdHBQYXJzZXJTdGF0ZS5PdXRwdXRCdWZmZXIgKz0gcENoYXJhY3Rlcjtcblx0fVxuXHRcblx0LyoqXG5cdCAqIEZsdXNoIHRoZSBvdXRwdXQgYnVmZmVyIHRvIHRoZSBvdXRwdXQgYW5kIGNsZWFyIGl0LlxuXHQgKiBAbWV0aG9kIGZsdXNoT3V0cHV0QnVmZmVyXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwUGFyc2VyU3RhdGUgLSBUaGUgc3RhdGUgb2JqZWN0IGZvciB0aGUgY3VycmVudCBwYXJzaW5nIHRhc2tcblx0ICogQHByaXZhdGVcblx0ICovXG5cdGZsdXNoT3V0cHV0QnVmZmVyIChwUGFyc2VyU3RhdGUpXG5cdHtcblx0XHRwUGFyc2VyU3RhdGUuT3V0cHV0ICs9IHBQYXJzZXJTdGF0ZS5PdXRwdXRCdWZmZXI7XG5cdFx0cFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlciA9ICcnO1xuXHR9XG5cblx0XG5cdC8qKlxuXHQgKiBDaGVjayBpZiB0aGUgcGF0dGVybiBoYXMgZW5kZWQuICBJZiBpdCBoYXMsIHByb3Blcmx5IGZsdXNoIHRoZSBidWZmZXIgYW5kIHN0YXJ0IGxvb2tpbmcgZm9yIG5ldyBwYXR0ZXJucy5cblx0ICogQG1ldGhvZCBjaGVja1BhdHRlcm5FbmRcblx0ICogQHBhcmFtIHtPYmplY3R9IHBQYXJzZXJTdGF0ZSAtIFRoZSBzdGF0ZSBvYmplY3QgZm9yIHRoZSBjdXJyZW50IHBhcnNpbmcgdGFza1xuXHQgKiBAcHJpdmF0ZVxuXHQgKi9cblx0Y2hlY2tQYXR0ZXJuRW5kIChwUGFyc2VyU3RhdGUpXG5cdHtcblx0XHRpZiAoKHBQYXJzZXJTdGF0ZS5PdXRwdXRCdWZmZXIubGVuZ3RoID49IHBQYXJzZXJTdGF0ZS5QYXR0ZXJuLlBhdHRlcm5FbmQubGVuZ3RoK3BQYXJzZXJTdGF0ZS5QYXR0ZXJuLlBhdHRlcm5TdGFydC5sZW5ndGgpICYmIFxuXHRcdFx0KHBQYXJzZXJTdGF0ZS5PdXRwdXRCdWZmZXIuc3Vic3RyKC1wUGFyc2VyU3RhdGUuUGF0dGVybi5QYXR0ZXJuRW5kLmxlbmd0aCkgPT09IHBQYXJzZXJTdGF0ZS5QYXR0ZXJuLlBhdHRlcm5FbmQpKVxuXHRcdHtcblx0XHRcdC8vIC4uLiB0aGlzIGlzIHRoZSBlbmQgb2YgYSBwYXR0ZXJuLCBjdXQgb2ZmIHRoZSBlbmQgdGFnIGFuZCBwYXJzZSBpdC5cblx0XHRcdC8vIFRyaW0gdGhlIHN0YXJ0IGFuZCBlbmQgdGFncyBvZmYgdGhlIG91dHB1dCBidWZmZXIgbm93XG5cdFx0XHRwUGFyc2VyU3RhdGUuT3V0cHV0QnVmZmVyID0gcFBhcnNlclN0YXRlLlBhdHRlcm4uUGFyc2UocFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlci5zdWJzdHIocFBhcnNlclN0YXRlLlBhdHRlcm4uUGF0dGVyblN0YXJ0Lmxlbmd0aCwgcFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlci5sZW5ndGggLSAocFBhcnNlclN0YXRlLlBhdHRlcm4uUGF0dGVyblN0YXJ0Lmxlbmd0aCtwUGFyc2VyU3RhdGUuUGF0dGVybi5QYXR0ZXJuRW5kLmxlbmd0aCkpKTtcblx0XHRcdC8vIEZsdXNoIHRoZSBvdXRwdXQgYnVmZmVyLlxuXHRcdFx0dGhpcy5mbHVzaE91dHB1dEJ1ZmZlcihwUGFyc2VyU3RhdGUpO1xuXHRcdFx0Ly8gRW5kIHBhdHRlcm4gbW9kZVxuXHRcdFx0cFBhcnNlclN0YXRlLlBhdHRlcm4gPSBmYWxzZTtcblx0XHRcdHBQYXJzZXJTdGF0ZS5QYXR0ZXJuTWF0Y2ggPSBmYWxzZTtcblx0XHR9XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBQYXJzZSBhIGNoYXJhY3RlciBpbiB0aGUgYnVmZmVyLlxuXHQgKiBAbWV0aG9kIHBhcnNlQ2hhcmFjdGVyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwQ2hhcmFjdGVyIC0gVGhlIGNoYXJhY3RlciB0byBhcHBlbmRcblx0ICogQHBhcmFtIHtPYmplY3R9IHBQYXJzZXJTdGF0ZSAtIFRoZSBzdGF0ZSBvYmplY3QgZm9yIHRoZSBjdXJyZW50IHBhcnNpbmcgdGFza1xuXHQgKiBAcHJpdmF0ZVxuXHQgKi9cblx0cGFyc2VDaGFyYWN0ZXIgKHBDaGFyYWN0ZXIsIHBQYXJzZXJTdGF0ZSlcblx0e1xuXHRcdC8vICgxKSBJZiB3ZSBhcmVuJ3QgaW4gYSBwYXR0ZXJuIG1hdGNoLCBhbmQgd2UgYXJlbid0IHBvdGVudGlhbGx5IG1hdGNoaW5nLCBhbmQgdGhpcyBtYXkgYmUgdGhlIHN0YXJ0IG9mIGEgbmV3IHBhdHRlcm4uLi4uXG5cdFx0aWYgKCFwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoICYmIHBQYXJzZXJTdGF0ZS5QYXJzZVRyZWUuaGFzT3duUHJvcGVydHkocENoYXJhY3RlcikpXG5cdFx0e1xuXHRcdFx0Ly8gLi4uIGFzc2lnbiB0aGUgbm9kZSBhcyB0aGUgbWF0Y2hlZCBub2RlLlxuXHRcdFx0dGhpcy5hc3NpZ25Ob2RlKHBQYXJzZXJTdGF0ZS5QYXJzZVRyZWVbcENoYXJhY3Rlcl0sIHBQYXJzZXJTdGF0ZSk7XG5cdFx0XHR0aGlzLmFwcGVuZE91dHB1dEJ1ZmZlcihwQ2hhcmFjdGVyLCBwUGFyc2VyU3RhdGUpO1xuXHRcdH1cblx0XHQvLyAoMikgSWYgd2UgYXJlIGluIGEgcGF0dGVybiBtYXRjaCAoYWN0aXZlbHkgc2VlaW5nIGlmIHRoaXMgaXMgcGFydCBvZiBhIG5ldyBwYXR0ZXJuIHRva2VuKVxuXHRcdGVsc2UgaWYgKHBQYXJzZXJTdGF0ZS5QYXR0ZXJuTWF0Y2gpXG5cdFx0e1xuXHRcdFx0Ly8gSWYgdGhlIHBhdHRlcm4gaGFzIGEgc3VicGF0dGVybiB3aXRoIHRoaXMga2V5XG5cdFx0XHRpZiAocFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaC5oYXNPd25Qcm9wZXJ0eShwQ2hhcmFjdGVyKSlcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ29udGludWUgbWF0Y2hpbmcgcGF0dGVybnMuXG5cdFx0XHRcdHRoaXMuYXNzaWduTm9kZShwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoW3BDaGFyYWN0ZXJdLCBwUGFyc2VyU3RhdGUpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5hcHBlbmRPdXRwdXRCdWZmZXIocENoYXJhY3RlciwgcFBhcnNlclN0YXRlKTtcblx0XHRcdGlmIChwUGFyc2VyU3RhdGUuUGF0dGVybilcblx0XHRcdHtcblx0XHRcdFx0Ly8gLi4uIENoZWNrIGlmIHRoaXMgaXMgdGhlIGVuZCBvZiB0aGUgcGF0dGVybiAoaWYgd2UgYXJlIG1hdGNoaW5nIGEgdmFsaWQgcGF0dGVybikuLi5cblx0XHRcdFx0dGhpcy5jaGVja1BhdHRlcm5FbmQocFBhcnNlclN0YXRlKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0Ly8gKDMpIElmIHdlIGFyZW4ndCBpbiBhIHBhdHRlcm4gbWF0Y2ggb3IgcGF0dGVybiwgYW5kIHRoaXMgaXNuJ3QgdGhlIHN0YXJ0IG9mIGEgbmV3IHBhdHRlcm4gKFJBVyBtb2RlKS4uLi5cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0cFBhcnNlclN0YXRlLk91dHB1dCArPSBwQ2hhcmFjdGVyO1xuXHRcdH1cblx0fVxuXHRcblx0LyoqXG5cdCAqIFBhcnNlIGEgc3RyaW5nIGZvciBtYXRjaGVzLCBhbmQgcHJvY2VzcyBhbnkgdGVtcGxhdGUgc2VnbWVudHMgdGhhdCBvY2N1ci5cblx0ICogQG1ldGhvZCBwYXJzZVN0cmluZ1xuXHQgKiBAcGFyYW0ge3N0cmluZ30gcFN0cmluZyAtIFRoZSBzdHJpbmcgdG8gcGFyc2UuXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwUGFyc2VUcmVlIC0gVGhlIHBhcnNlIHRyZWUgdG8gYmVnaW4gcGFyc2luZyBmcm9tICh1c3VhbGx5IHJvb3QpXG5cdCAqL1xuXHRwYXJzZVN0cmluZyAocFN0cmluZywgcFBhcnNlVHJlZSlcblx0e1xuXHRcdGxldCB0bXBQYXJzZXJTdGF0ZSA9IHRoaXMubmV3UGFyc2VyU3RhdGUocFBhcnNlVHJlZSk7XG5cblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHBTdHJpbmcubGVuZ3RoOyBpKyspXG5cdFx0e1xuXHRcdFx0Ly8gVE9ETzogVGhpcyBpcyBub3QgZmFzdC5cblx0XHRcdHRoaXMucGFyc2VDaGFyYWN0ZXIocFN0cmluZ1tpXSwgdG1wUGFyc2VyU3RhdGUpO1xuXHRcdH1cblx0XHRcblx0XHR0aGlzLmZsdXNoT3V0cHV0QnVmZmVyKHRtcFBhcnNlclN0YXRlKTtcblx0XHRcblx0XHRyZXR1cm4gdG1wUGFyc2VyU3RhdGUuT3V0cHV0O1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyaW5nUGFyc2VyO1xuIiwiLyoqXG4qIFdvcmQgVHJlZVxuKlxuKiBAbGljZW5zZSAgICAgTUlUXG4qXG4qIEBhdXRob3IgICAgICBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbipcbiogQGRlc2NyaXB0aW9uIENyZWF0ZSBhIHRyZWUgKGRpcmVjdGVkIGdyYXBoKSBvZiBKYXZhc2NyaXB0IG9iamVjdHMsIG9uZSBjaGFyYWN0ZXIgcGVyIG9iamVjdC5cbiovXG5cbmNsYXNzIFdvcmRUcmVlXG57XG5cdC8qKlxuXHQgKiBXb3JkVHJlZSBDb25zdHJ1Y3RvclxuXHQgKi9cblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdFx0dGhpcy5QYXJzZVRyZWUgPSB7fTtcblx0fVxuXHRcblx0LyoqIFxuXHQgKiBBZGQgYSBjaGlsZCBjaGFyYWN0ZXIgdG8gYSBQYXJzZSBUcmVlIG5vZGVcblx0ICogQG1ldGhvZCBhZGRDaGlsZFxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFRyZWUgLSBBIHBhcnNlIHRyZWUgdG8gcHVzaCB0aGUgY2hhcmFjdGVycyBpbnRvXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwUGF0dGVybiAtIFRoZSBzdHJpbmcgdG8gYWRkIHRvIHRoZSB0cmVlXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBwSW5kZXggLSBjYWxsYmFjayBmdW5jdGlvblxuXHQgKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcmVzdWx0aW5nIGxlYWYgbm9kZSB0aGF0IHdhcyBhZGRlZCAob3IgZm91bmQpXG5cdCAqIEBwcml2YXRlXG5cdCAqL1xuXHRhZGRDaGlsZCAocFRyZWUsIHBQYXR0ZXJuLCBwSW5kZXgpXG5cdHtcblx0XHRpZiAocEluZGV4ID4gcFBhdHRlcm4ubGVuZ3RoKVxuXHRcdFx0cmV0dXJuIHBUcmVlO1xuXHRcdFxuXHRcdGlmICghcFRyZWUuaGFzT3duUHJvcGVydHkocFBhdHRlcm5bcEluZGV4XSkpXG5cdFx0XHRwVHJlZVtwUGF0dGVybltwSW5kZXhdXSA9IHt9O1xuXHRcdFxuXHRcdHJldHVybiBwVHJlZVtwUGF0dGVybltwSW5kZXhdXTtcblx0fVxuXHRcblx0LyoqIEFkZCBhIFBhdHRlcm4gdG8gdGhlIFBhcnNlIFRyZWVcblx0ICogQG1ldGhvZCBhZGRQYXR0ZXJuXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwVHJlZSAtIEEgbm9kZSBvbiB0aGUgcGFyc2UgdHJlZSB0byBwdXNoIHRoZSBjaGFyYWN0ZXJzIGludG9cblx0ICogQHBhcmFtIHtzdHJpbmd9IHBQYXR0ZXJuIC0gVGhlIHN0cmluZyB0byBhZGQgdG8gdGhlIHRyZWVcblx0ICogQHBhcmFtIHtudW1iZXJ9IHBJbmRleCAtIGNhbGxiYWNrIGZ1bmN0aW9uXG5cdCAqIEByZXR1cm4ge2Jvb2x9IFRydWUgaWYgYWRkaW5nIHRoZSBwYXR0ZXJuIHdhcyBzdWNjZXNzZnVsXG5cdCAqL1xuXHRhZGRQYXR0ZXJuIChwUGF0dGVyblN0YXJ0LCBwUGF0dGVybkVuZCwgcFBhcnNlcilcblx0e1xuXHRcdGlmIChwUGF0dGVyblN0YXJ0Lmxlbmd0aCA8IDEpXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHRsZXQgdG1wTGVhZiA9IHRoaXMuUGFyc2VUcmVlO1xuXG5cdFx0Ly8gQWRkIHRoZSB0cmVlIG9mIGxlYXZlcyBpdGVyYXRpdmVseVxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgcFBhdHRlcm5TdGFydC5sZW5ndGg7IGkrKylcblx0XHRcdHRtcExlYWYgPSB0aGlzLmFkZENoaWxkKHRtcExlYWYsIHBQYXR0ZXJuU3RhcnQsIGkpO1xuXG5cdFx0dG1wTGVhZi5QYXR0ZXJuU3RhcnQgPSBwUGF0dGVyblN0YXJ0O1xuXHRcdHRtcExlYWYuUGF0dGVybkVuZCA9ICgodHlwZW9mKHBQYXR0ZXJuRW5kKSA9PT0gJ3N0cmluZycpICYmIChwUGF0dGVybkVuZC5sZW5ndGggPiAwKSkgPyBwUGF0dGVybkVuZCA6IHBQYXR0ZXJuU3RhcnQ7XG5cdFx0dG1wTGVhZi5QYXJzZSA9ICh0eXBlb2YocFBhcnNlcikgPT09ICdmdW5jdGlvbicpID8gcFBhcnNlciA6IFxuXHRcdFx0XHRcdFx0KHR5cGVvZihwUGFyc2VyKSA9PT0gJ3N0cmluZycpID8gKCkgPT4geyByZXR1cm4gcFBhcnNlcjsgfSA6XG5cdFx0XHRcdFx0XHQocERhdGEpID0+IHsgcmV0dXJuIHBEYXRhOyB9O1xuXG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBXb3JkVHJlZTtcbiJdfQ==
|