precedent 1.0.14 → 1.0.16
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 +5 -0
- package/CONTRIBUTING.md +50 -0
- package/README.md +116 -43
- package/docs/.nojekyll +0 -0
- package/docs/README.md +142 -0
- package/docs/_sidebar.md +19 -0
- package/docs/_topbar.md +5 -0
- package/docs/api.md +209 -0
- package/docs/cover.md +15 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/examples.md +429 -0
- package/docs/index.html +39 -0
- package/docs/retold-catalog.json +70 -0
- package/docs/retold-keyword-index.json +19 -0
- package/package.json +49 -62
- package/source/StringParser.js +92 -61
- package/source/WordTree.js +50 -12
- package/test/Precedent_tests.js +0 -3
- package/.browserslistrc_compatible +0 -1
- package/.browserslistrc_default +0 -1
- package/.travis.yml +0 -13
- package/Ideas.md +0 -4
- package/bower.json +0 -27
- package/dist/precedent.compatible.js +0 -310
- package/dist/precedent.compatible.min.js +0 -12
- package/dist/precedent.compatible.min.js.map +0 -1
- package/dist/precedent.js +0 -310
- package/dist/precedent.min.js +0 -12
- package/dist/precedent.min.js.map +0 -1
- package/gulpfile-config.json +0 -11
- package/gulpfile-config_compatible.json +0 -11
- package/gulpfile-config_default.json +0 -11
- package/gulpfile.js +0 -164
package/package.json
CHANGED
|
@@ -1,65 +1,52 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
"author": "Steven Velozo <steven@velozo.com>",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/stevenvelozo/precedent/issues"
|
|
29
|
-
},
|
|
30
|
-
"mocha": {
|
|
31
|
-
"diff": true,
|
|
32
|
-
"extension": [
|
|
33
|
-
"js"
|
|
2
|
+
"name": "precedent",
|
|
3
|
+
"version": "1.0.16",
|
|
4
|
+
"description": "Precedent Meta-Templating",
|
|
5
|
+
"main": "source/Precedent.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"precedent": "./bin/Precedent"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node source/Precedent.js",
|
|
11
|
+
"coverage": "./node_modules/.bin/nyc --reporter=lcov --reporter=text-lcov ./node_modules/mocha/bin/_mocha -- -u tdd -R spec",
|
|
12
|
+
"test": "./node_modules/.bin/mocha -u tdd -R spec",
|
|
13
|
+
"docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/precedent:local",
|
|
14
|
+
"docker-dev-run": "docker run -it -d --name precedent-dev -p 30001:8080 -p 38086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/precedent\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" precedent-image:local",
|
|
15
|
+
"build": "npx quack build",
|
|
16
|
+
"docker-dev-build": "docker build ./ -f Dockerfile_LUXURYCode -t precedent-image:local",
|
|
17
|
+
"docker-dev-shell": "docker exec -it precedent-dev /bin/bash"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/stevenvelozo/precedent.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"logging"
|
|
34
25
|
],
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"vinyl-buffer": "^1.0.1",
|
|
62
|
-
"vinyl-source-stream": "^2.0.0"
|
|
63
|
-
},
|
|
64
|
-
"dependencies": {}
|
|
26
|
+
"author": "Steven Velozo <steven@velozo.com>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/stevenvelozo/precedent/issues"
|
|
30
|
+
},
|
|
31
|
+
"mocha": {
|
|
32
|
+
"diff": true,
|
|
33
|
+
"extension": [
|
|
34
|
+
"js"
|
|
35
|
+
],
|
|
36
|
+
"package": "./package.json",
|
|
37
|
+
"reporter": "spec",
|
|
38
|
+
"slow": "75",
|
|
39
|
+
"timeout": "5000",
|
|
40
|
+
"ui": "tdd",
|
|
41
|
+
"watch-files": [
|
|
42
|
+
"source/**/*.js",
|
|
43
|
+
"test/**/*.js"
|
|
44
|
+
],
|
|
45
|
+
"watch-ignore": [
|
|
46
|
+
"lib/vendor"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"quackage": "^1.0.48"
|
|
51
|
+
}
|
|
65
52
|
}
|
package/source/StringParser.js
CHANGED
|
@@ -31,33 +31,13 @@ class StringParser
|
|
|
31
31
|
Output: '',
|
|
32
32
|
OutputBuffer: '',
|
|
33
33
|
|
|
34
|
-
Pattern:
|
|
34
|
+
Pattern: {},
|
|
35
35
|
|
|
36
36
|
PatternMatch: false,
|
|
37
|
-
|
|
37
|
+
PatternMatchEnd: false
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Assign a node of the parser tree to be the next potential match.
|
|
43
|
-
* If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
|
|
44
|
-
* @method assignNode
|
|
45
|
-
* @param {Object} pNode - A node on the parse tree to assign
|
|
46
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
assignNode (pNode, pParserState)
|
|
50
|
-
{
|
|
51
|
-
pParserState.PatternMatch = pNode;
|
|
52
|
-
|
|
53
|
-
// If the pattern has a END we can assume it has a parse function...
|
|
54
|
-
if (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))
|
|
55
|
-
{
|
|
56
|
-
// ... this is the legitimate start of a pattern.
|
|
57
|
-
pParserState.Pattern = pParserState.PatternMatch;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
41
|
/**
|
|
62
42
|
* Append a character to the output buffer in the parser state.
|
|
63
43
|
* This output buffer is used when a potential match is being explored, or a match is being explored.
|
|
@@ -83,26 +63,18 @@ class StringParser
|
|
|
83
63
|
pParserState.OutputBuffer = '';
|
|
84
64
|
}
|
|
85
65
|
|
|
86
|
-
|
|
87
|
-
* Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
|
|
88
|
-
* @method checkPatternEnd
|
|
89
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
90
|
-
* @private
|
|
91
|
-
*/
|
|
92
|
-
checkPatternEnd (pParserState, pData)
|
|
66
|
+
resetOutputBuffer (pParserState)
|
|
93
67
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
pParserState.PatternMatch = false;
|
|
105
|
-
}
|
|
68
|
+
// Flush the output buffer.
|
|
69
|
+
this.flushOutputBuffer(pParserState);
|
|
70
|
+
// End pattern mode
|
|
71
|
+
pParserState.Pattern = false;
|
|
72
|
+
pParserState.PatternStartNode = false;
|
|
73
|
+
pParserState.StartPatternMatchComplete = false;
|
|
74
|
+
pParserState.EndPatternMatchBegan = false;
|
|
75
|
+
pParserState.PatternMatch = false;
|
|
76
|
+
|
|
77
|
+
return true;
|
|
106
78
|
}
|
|
107
79
|
|
|
108
80
|
/**
|
|
@@ -114,34 +86,93 @@ class StringParser
|
|
|
114
86
|
*/
|
|
115
87
|
parseCharacter (pCharacter, pParserState, pData)
|
|
116
88
|
{
|
|
117
|
-
//
|
|
118
|
-
if (
|
|
89
|
+
// If we are already in a pattern match traversal
|
|
90
|
+
if (pParserState.PatternMatch)
|
|
119
91
|
{
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// If the pattern has a subpattern with this key
|
|
128
|
-
if (pParserState.PatternMatch.hasOwnProperty(pCharacter))
|
|
92
|
+
// If the pattern is still matching the start and we haven't passed the buffer
|
|
93
|
+
if (!pParserState.StartPatternMatchComplete && pParserState.Pattern.hasOwnProperty(pCharacter))
|
|
94
|
+
{
|
|
95
|
+
pParserState.Pattern = pParserState.Pattern[pCharacter];
|
|
96
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
97
|
+
}
|
|
98
|
+
else if (pParserState.EndPatternMatchBegan)
|
|
129
99
|
{
|
|
130
|
-
|
|
131
|
-
|
|
100
|
+
if (pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter))
|
|
101
|
+
{
|
|
102
|
+
// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
103
|
+
pParserState.Pattern = pParserState.Pattern.PatternEnd[pCharacter];
|
|
104
|
+
// Flush the output buffer.
|
|
105
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
106
|
+
// If this last character is the end of the pattern, parse it.
|
|
107
|
+
if (pParserState.Pattern.hasOwnProperty('Parse'))
|
|
108
|
+
{
|
|
109
|
+
// Run the function
|
|
110
|
+
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData);
|
|
111
|
+
return this.resetOutputBuffer(pParserState);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter))
|
|
115
|
+
{
|
|
116
|
+
// We broke out of the end -- see if this is a new start of the end.
|
|
117
|
+
pParserState.Pattern = pParserState.PatternStartNode.PatternEnd[pCharacter];
|
|
118
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
119
|
+
}
|
|
120
|
+
else
|
|
121
|
+
{
|
|
122
|
+
pParserState.EndPatternMatchBegan = false;
|
|
123
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
124
|
+
}
|
|
132
125
|
}
|
|
133
|
-
|
|
134
|
-
if (pParserState.Pattern)
|
|
126
|
+
else if (pParserState.Pattern.hasOwnProperty('PatternEnd'))
|
|
135
127
|
{
|
|
136
|
-
|
|
137
|
-
|
|
128
|
+
if (!pParserState.StartPatternMatchComplete)
|
|
129
|
+
{
|
|
130
|
+
pParserState.StartPatternMatchComplete = true;
|
|
131
|
+
pParserState.PatternStartNode = pParserState.Pattern;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
135
|
+
|
|
136
|
+
if (pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter))
|
|
137
|
+
{
|
|
138
|
+
// This is the first character of the end pattern.
|
|
139
|
+
pParserState.EndPatternMatchBegan = true;
|
|
140
|
+
// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
141
|
+
pParserState.Pattern = pParserState.Pattern.PatternEnd[pCharacter];
|
|
142
|
+
// If this last character is the end of the pattern, parse it.
|
|
143
|
+
if (pParserState.Pattern.hasOwnProperty('Parse'))
|
|
144
|
+
{
|
|
145
|
+
// Run the t*mplate function
|
|
146
|
+
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData);
|
|
147
|
+
return this.resetOutputBuffer(pParserState);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else
|
|
152
|
+
{
|
|
153
|
+
// We are in a pattern start but didn't match one; reset and start trying again from this character.
|
|
154
|
+
this.resetOutputBuffer(pParserState);
|
|
138
155
|
}
|
|
139
156
|
}
|
|
140
|
-
//
|
|
141
|
-
|
|
157
|
+
// If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
|
|
158
|
+
if (!pParserState.PatternMatch)
|
|
142
159
|
{
|
|
143
|
-
|
|
160
|
+
// This may be the start of a new pattern....
|
|
161
|
+
if (pParserState.ParseTree.hasOwnProperty(pCharacter))
|
|
162
|
+
{
|
|
163
|
+
// ... assign the root node as the matched node.
|
|
164
|
+
this.resetOutputBuffer(pParserState);
|
|
165
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
166
|
+
pParserState.Pattern = pParserState.ParseTree[pCharacter];
|
|
167
|
+
pParserState.PatternMatch = true;
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
else
|
|
171
|
+
{
|
|
172
|
+
this.appendOutputBuffer(pCharacter, pParserState);
|
|
173
|
+
}
|
|
144
174
|
}
|
|
175
|
+
return false;
|
|
145
176
|
}
|
|
146
177
|
|
|
147
178
|
/**
|
package/source/WordTree.js
CHANGED
|
@@ -19,43 +19,81 @@ class WordTree
|
|
|
19
19
|
* @method addChild
|
|
20
20
|
* @param {Object} pTree - A parse tree to push the characters into
|
|
21
21
|
* @param {string} pPattern - The string to add to the tree
|
|
22
|
-
* @param {number} pIndex - The index of the character in the pattern
|
|
23
22
|
* @returns {Object} The resulting leaf node that was added (or found)
|
|
24
23
|
* @private
|
|
25
24
|
*/
|
|
26
|
-
addChild (pTree, pPattern
|
|
25
|
+
addChild (pTree, pPattern)
|
|
27
26
|
{
|
|
28
|
-
if (!pTree.hasOwnProperty(pPattern
|
|
29
|
-
|
|
27
|
+
if (!pTree.hasOwnProperty(pPattern))
|
|
28
|
+
{
|
|
29
|
+
pTree[pPattern] = {};
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
return pTree[pPattern
|
|
32
|
+
return pTree[pPattern];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Add a child character to a Parse Tree PatternEnd subtree
|
|
37
|
+
* @method addChild
|
|
38
|
+
* @param {Object} pTree - A parse tree to push the characters into
|
|
39
|
+
* @param {string} pPattern - The string to add to the tree
|
|
40
|
+
* @returns {Object} The resulting leaf node that was added (or found)
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
addEndChild (pTree, pPattern)
|
|
44
|
+
{
|
|
45
|
+
if (!pTree.hasOwnProperty('PatternEnd'))
|
|
46
|
+
{
|
|
47
|
+
pTree.PatternEnd = {};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pTree.PatternEnd[pPattern] = {};
|
|
51
|
+
|
|
52
|
+
return pTree.PatternEnd[pPattern];
|
|
32
53
|
}
|
|
33
54
|
|
|
34
55
|
/** Add a Pattern to the Parse Tree
|
|
35
56
|
* @method addPattern
|
|
36
57
|
* @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
|
|
37
58
|
* @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
|
|
38
|
-
* @param {
|
|
59
|
+
* @param {function} fParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.
|
|
39
60
|
* @return {bool} True if adding the pattern was successful
|
|
40
61
|
*/
|
|
41
|
-
addPattern (pPatternStart, pPatternEnd,
|
|
62
|
+
addPattern (pPatternStart, pPatternEnd, fParser)
|
|
42
63
|
{
|
|
43
64
|
if (pPatternStart.length < 1)
|
|
65
|
+
{
|
|
44
66
|
return false;
|
|
67
|
+
}
|
|
45
68
|
|
|
46
69
|
if ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1))
|
|
70
|
+
{
|
|
47
71
|
return false;
|
|
72
|
+
}
|
|
48
73
|
|
|
49
74
|
let tmpLeaf = this.ParseTree;
|
|
50
75
|
|
|
51
76
|
// Add the tree of leaves iteratively
|
|
52
77
|
for (var i = 0; i < pPatternStart.length; i++)
|
|
53
|
-
|
|
78
|
+
{
|
|
79
|
+
tmpLeaf = this.addChild(tmpLeaf, pPatternStart[i], i);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!tmpLeaf.hasOwnProperty('PatternEnd'))
|
|
83
|
+
{
|
|
84
|
+
tmpLeaf.PatternEnd = {};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let tmpPatternEnd = (typeof(pPatternEnd) === 'string') ? pPatternEnd : pPatternStart;
|
|
88
|
+
for (let i = 0; i < tmpPatternEnd.length; i++)
|
|
89
|
+
{
|
|
90
|
+
tmpLeaf = this.addEndChild(tmpLeaf, tmpPatternEnd[i], i);
|
|
91
|
+
}
|
|
54
92
|
|
|
55
|
-
tmpLeaf.
|
|
56
|
-
tmpLeaf.
|
|
57
|
-
tmpLeaf.Parse = (typeof(
|
|
58
|
-
(typeof(
|
|
93
|
+
tmpLeaf.PatternStartString = pPatternStart;
|
|
94
|
+
tmpLeaf.PatternEndString = tmpPatternEnd;
|
|
95
|
+
tmpLeaf.Parse = (typeof(fParser) === 'function') ? fParser :
|
|
96
|
+
(typeof(fParser) === 'string') ? () => { return fParser; } :
|
|
59
97
|
(pData) => { return pData; };
|
|
60
98
|
|
|
61
99
|
return true;
|
package/test/Precedent_tests.js
CHANGED
|
@@ -191,9 +191,6 @@ suite
|
|
|
191
191
|
'Match this <<> and this <<here> please.',
|
|
192
192
|
'Match this MEDIUM_MATCH and this MEDIUM_MATCH please.',
|
|
193
193
|
|
|
194
|
-
'Match this <<EXTRA> and this <<here> please.',
|
|
195
|
-
'Match this MEDIUM_MATCH and this MEDIUM_MATCH please.',
|
|
196
|
-
|
|
197
194
|
'Match this <<EXTRALONG> and this <<here> please.',
|
|
198
195
|
'Match this EXTRA_LONG_MATCH and this MEDIUM_MATCH please.',
|
|
199
196
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
> 0.01%
|
package/.browserslistrc_default
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
since 2018
|
package/.travis.yml
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
node_js:
|
|
3
|
-
- "6"
|
|
4
|
-
addons:
|
|
5
|
-
code_climate:
|
|
6
|
-
repo_token: bfa5c3ab7995e040fe79b41988e937679639f1de21a76a531aad4db19e2b928f
|
|
7
|
-
after_success:
|
|
8
|
-
- npm run coverage
|
|
9
|
-
after_script:
|
|
10
|
-
- cat coverage/lcov.info | ./node_modules/codeclimate-test-reporter/bin/codeclimate.js
|
|
11
|
-
- cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
|
12
|
-
notifications:
|
|
13
|
-
slack: paviateam:C1q99hL9XXpiPpau2PUrVZPC
|
package/Ideas.md
DELETED
package/bower.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "precedent",
|
|
3
|
-
"version": "1.0.5",
|
|
4
|
-
"description": "Precedent metatemplating library",
|
|
5
|
-
"main": "dist/precedent.latest.min.js",
|
|
6
|
-
"authors": [
|
|
7
|
-
"steven velozo <steven@velozo.com>"
|
|
8
|
-
],
|
|
9
|
-
"license": "MIT",
|
|
10
|
-
"homepage": "https://github.com/stevenvelozo/precedent",
|
|
11
|
-
"moduleType": [
|
|
12
|
-
"globals",
|
|
13
|
-
"node"
|
|
14
|
-
],
|
|
15
|
-
"ignore": [
|
|
16
|
-
"**/.*",
|
|
17
|
-
"node_modules",
|
|
18
|
-
"bower_components",
|
|
19
|
-
"bin",
|
|
20
|
-
"source",
|
|
21
|
-
"coverage",
|
|
22
|
-
"test",
|
|
23
|
-
"tests"
|
|
24
|
-
],
|
|
25
|
-
"dependencies": {
|
|
26
|
-
}
|
|
27
|
-
}
|