@featurevisor/core 2.6.7 → 2.8.0
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/CHANGELOG.md +22 -0
- package/coverage/clover.xml +145 -474
- package/coverage/coverage-final.json +4 -10
- package/coverage/lcov-report/{src/builder → builder}/allocator.ts.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/buildScopedConditions.ts.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/buildScopedDatafile.ts.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/buildScopedSegments.ts.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/index.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/revision.ts.html +10 -10
- package/coverage/lcov-report/{src/builder → builder}/traffic.ts.html +10 -10
- package/coverage/lcov-report/index.html +35 -65
- package/coverage/lcov-report/{src/list → list}/index.html +24 -24
- package/coverage/lcov-report/{src/list → list}/matrix.ts.html +27 -18
- package/coverage/lcov-report/{lib/tester → parsers}/index.html +41 -26
- package/coverage/lcov-report/parsers/json.ts.html +118 -0
- package/coverage/lcov-report/parsers/yml.ts.html +589 -0
- package/coverage/lcov-report/{src/tester → tester}/helpers.ts.html +10 -10
- package/coverage/lcov-report/{src/tester → tester}/index.html +10 -10
- package/coverage/lcov.info +246 -899
- package/jest.config.js +1 -0
- package/lib/config/index.d.ts +0 -1
- package/lib/config/index.js +0 -1
- package/lib/config/index.js.map +1 -1
- package/lib/config/projectConfig.d.ts +1 -1
- package/lib/config/projectConfig.js +1 -1
- package/lib/config/projectConfig.js.map +1 -1
- package/lib/datasource/datasource.js.map +1 -1
- package/lib/datasource/filesystemAdapter.js +1 -1
- package/lib/datasource/filesystemAdapter.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/linter/conditionSchema.js +45 -6
- package/lib/linter/conditionSchema.js.map +1 -1
- package/lib/linter/testSchema.d.ts +5 -0
- package/lib/linter/testSchema.js +6 -1
- package/lib/linter/testSchema.js.map +1 -1
- package/lib/list/matrix.js +4 -1
- package/lib/list/matrix.js.map +1 -1
- package/lib/{config/parsers.d.ts → parsers/index.d.ts} +5 -5
- package/lib/parsers/index.js +15 -0
- package/lib/parsers/index.js.map +1 -0
- package/lib/parsers/json.d.ts +2 -0
- package/lib/parsers/json.js +13 -0
- package/lib/parsers/json.js.map +1 -0
- package/lib/parsers/json.spec.d.ts +1 -0
- package/lib/parsers/json.spec.js +35 -0
- package/lib/parsers/json.spec.js.map +1 -0
- package/lib/parsers/yml.d.ts +2 -0
- package/lib/parsers/yml.js +154 -0
- package/lib/parsers/yml.js.map +1 -0
- package/lib/parsers/yml.spec.d.ts +1 -0
- package/lib/parsers/yml.spec.js +143 -0
- package/lib/parsers/yml.spec.js.map +1 -0
- package/lib/tester/testFeature.js +6 -1
- package/lib/tester/testFeature.js.map +1 -1
- package/lib/tester/testProject.d.ts +1 -0
- package/lib/tester/testProject.js +28 -2
- package/lib/tester/testProject.js.map +1 -1
- package/lib/utils/git.js.map +1 -1
- package/package.json +6 -6
- package/src/config/index.ts +0 -1
- package/src/config/projectConfig.ts +1 -1
- package/src/datasource/datasource.ts +2 -1
- package/src/datasource/filesystemAdapter.ts +3 -2
- package/src/index.ts +1 -0
- package/src/linter/conditionSchema.ts +43 -6
- package/src/linter/testSchema.ts +9 -1
- package/src/list/matrix.ts +4 -1
- package/src/parsers/index.ts +22 -0
- package/src/parsers/json.spec.ts +36 -0
- package/src/parsers/json.ts +11 -0
- package/src/parsers/yml.spec.ts +174 -0
- package/src/parsers/yml.ts +168 -0
- package/src/tester/testFeature.ts +6 -1
- package/src/tester/testProject.ts +41 -2
- package/src/utils/git.ts +2 -1
- package/coverage/lcov-report/lib/builder/allocator.js.html +0 -196
- package/coverage/lcov-report/lib/builder/buildScopedConditions.js.html +0 -373
- package/coverage/lcov-report/lib/builder/buildScopedDatafile.js.html +0 -403
- package/coverage/lcov-report/lib/builder/buildScopedSegments.js.html +0 -379
- package/coverage/lcov-report/lib/builder/index.html +0 -191
- package/coverage/lcov-report/lib/builder/revision.js.html +0 -148
- package/coverage/lcov-report/lib/builder/traffic.js.html +0 -493
- package/coverage/lcov-report/lib/list/index.html +0 -116
- package/coverage/lcov-report/lib/list/matrix.js.html +0 -523
- package/coverage/lcov-report/lib/tester/helpers.js.html +0 -295
- package/lib/config/parsers.js +0 -32
- package/lib/config/parsers.js.map +0 -1
- package/src/config/parsers.ts +0 -40
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<!doctype html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
|
|
5
|
-
<head>
|
|
6
|
-
<title>Code coverage report for lib/builder/revision.js</title>
|
|
7
|
-
<meta charset="utf-8" />
|
|
8
|
-
<link rel="stylesheet" href="../../prettify.css" />
|
|
9
|
-
<link rel="stylesheet" href="../../base.css" />
|
|
10
|
-
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
|
|
11
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
-
<style type='text/css'>
|
|
13
|
-
.coverage-summary .sorter {
|
|
14
|
-
background-image: url(../../sort-arrow-sprite.png);
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
</head>
|
|
18
|
-
|
|
19
|
-
<body>
|
|
20
|
-
<div class='wrapper'>
|
|
21
|
-
<div class='pad1'>
|
|
22
|
-
<h1><a href="../../index.html">All files</a> / <a href="index.html">lib/builder</a> revision.js</h1>
|
|
23
|
-
<div class='clearfix'>
|
|
24
|
-
|
|
25
|
-
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">90.9% </span>
|
|
27
|
-
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>10/11</span>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">87.5% </span>
|
|
34
|
-
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>7/8</span>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<div class='fl pad1y space-right2'>
|
|
40
|
-
<span class="strong">100% </span>
|
|
41
|
-
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>1/1</span>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<div class='fl pad1y space-right2'>
|
|
47
|
-
<span class="strong">90.9% </span>
|
|
48
|
-
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>10/11</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
<p class="quiet">
|
|
55
|
-
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
-
</p>
|
|
57
|
-
<template id="filterTemplate">
|
|
58
|
-
<div class="quiet">
|
|
59
|
-
Filter:
|
|
60
|
-
<input oninput="onInput()" type="search" id="fileSearch">
|
|
61
|
-
</div>
|
|
62
|
-
</template>
|
|
63
|
-
</div>
|
|
64
|
-
<div class='status-line high'></div>
|
|
65
|
-
<pre><table class="coverage">
|
|
66
|
-
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
-
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
-
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
-
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
-
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
-
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
-
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
-
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
-
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
-
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
-
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
-
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
-
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
-
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
-
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
-
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
-
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
-
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
-
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
-
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
-
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
-
<a name='L22'></a><a href='#L22'>22</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
88
|
-
<span class="cline-any cline-yes">1x</span>
|
|
89
|
-
<span class="cline-any cline-yes">1x</span>
|
|
90
|
-
<span class="cline-any cline-neutral"> </span>
|
|
91
|
-
<span class="cline-any cline-neutral"> </span>
|
|
92
|
-
<span class="cline-any cline-yes">7x</span>
|
|
93
|
-
<span class="cline-any cline-yes">2x</span>
|
|
94
|
-
<span class="cline-any cline-neutral"> </span>
|
|
95
|
-
<span class="cline-any cline-neutral"> </span>
|
|
96
|
-
<span class="cline-any cline-yes">5x</span>
|
|
97
|
-
<span class="cline-any cline-yes">2x</span>
|
|
98
|
-
<span class="cline-any cline-neutral"> </span>
|
|
99
|
-
<span class="cline-any cline-neutral"> </span>
|
|
100
|
-
<span class="cline-any cline-yes">3x</span>
|
|
101
|
-
<span class="cline-any cline-yes">3x</span>
|
|
102
|
-
<span class="cline-any cline-yes">3x</span>
|
|
103
|
-
<span class="cline-any cline-yes">3x</span>
|
|
104
|
-
<span class="cline-any cline-neutral"> </span>
|
|
105
|
-
<span class="cline-any cline-neutral"> </span>
|
|
106
|
-
<span class="cline-any cline-no"> </span>
|
|
107
|
-
<span class="cline-any cline-neutral"> </span>
|
|
108
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">"use strict";
|
|
109
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
110
|
-
exports.getNextRevision = getNextRevision;
|
|
111
|
-
function getNextRevision(currentRevision) {
|
|
112
|
-
// If the string is empty or can't be parsed with parseInt(), return "1".
|
|
113
|
-
if (!currentRevision || isNaN(parseInt(currentRevision, 10))) {
|
|
114
|
-
return "1";
|
|
115
|
-
}
|
|
116
|
-
// If the string is like an integer, increment it by 1 and return the value.
|
|
117
|
-
if (currentRevision.indexOf(".") === -1) {
|
|
118
|
-
return (parseInt(currentRevision, 10) + 1).toString();
|
|
119
|
-
}
|
|
120
|
-
// If the string is a semver, parse the patch version out of it, increment it by one and return it.
|
|
121
|
-
const parts = currentRevision.split(".");
|
|
122
|
-
const lastPart = parseInt(parts[parts.length - 1], 10);
|
|
123
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (!isNaN(lastPart)) {
|
|
124
|
-
return (lastPart + 1).toString();
|
|
125
|
-
}
|
|
126
|
-
// If the string can't be parsed as a semver, return "1".
|
|
127
|
-
<span class="cstat-no" title="statement not covered" > return "1";</span>
|
|
128
|
-
}
|
|
129
|
-
//# sourceMappingURL=revision.js.map</pre></td></tr></table></pre>
|
|
130
|
-
|
|
131
|
-
<div class='push'></div><!-- for sticky footer -->
|
|
132
|
-
</div><!-- /wrapper -->
|
|
133
|
-
<div class='footer quiet pad2 space-top1 center small'>
|
|
134
|
-
Code coverage generated by
|
|
135
|
-
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
136
|
-
at 2026-02-05T22:45:36.569Z
|
|
137
|
-
</div>
|
|
138
|
-
<script src="../../prettify.js"></script>
|
|
139
|
-
<script>
|
|
140
|
-
window.onload = function () {
|
|
141
|
-
prettyPrint();
|
|
142
|
-
};
|
|
143
|
-
</script>
|
|
144
|
-
<script src="../../sorter.js"></script>
|
|
145
|
-
<script src="../../block-navigation.js"></script>
|
|
146
|
-
</body>
|
|
147
|
-
</html>
|
|
148
|
-
|
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<!doctype html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
|
|
5
|
-
<head>
|
|
6
|
-
<title>Code coverage report for lib/builder/traffic.js</title>
|
|
7
|
-
<meta charset="utf-8" />
|
|
8
|
-
<link rel="stylesheet" href="../../prettify.css" />
|
|
9
|
-
<link rel="stylesheet" href="../../base.css" />
|
|
10
|
-
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
|
|
11
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
-
<style type='text/css'>
|
|
13
|
-
.coverage-summary .sorter {
|
|
14
|
-
background-image: url(../../sort-arrow-sprite.png);
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
</head>
|
|
18
|
-
|
|
19
|
-
<body>
|
|
20
|
-
<div class='wrapper'>
|
|
21
|
-
<div class='pad1'>
|
|
22
|
-
<h1><a href="../../index.html">All files</a> / <a href="index.html">lib/builder</a> traffic.js</h1>
|
|
23
|
-
<div class='clearfix'>
|
|
24
|
-
|
|
25
|
-
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">89.7% </span>
|
|
27
|
-
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>61/68</span>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">73.07% </span>
|
|
34
|
-
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>38/52</span>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<div class='fl pad1y space-right2'>
|
|
40
|
-
<span class="strong">100% </span>
|
|
41
|
-
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>12/12</span>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<div class='fl pad1y space-right2'>
|
|
47
|
-
<span class="strong">89.39% </span>
|
|
48
|
-
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>59/66</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
<p class="quiet">
|
|
55
|
-
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
-
</p>
|
|
57
|
-
<template id="filterTemplate">
|
|
58
|
-
<div class="quiet">
|
|
59
|
-
Filter:
|
|
60
|
-
<input oninput="onInput()" type="search" id="fileSearch">
|
|
61
|
-
</div>
|
|
62
|
-
</template>
|
|
63
|
-
</div>
|
|
64
|
-
<div class='status-line high'></div>
|
|
65
|
-
<pre><table class="coverage">
|
|
66
|
-
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
-
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
-
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
-
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
-
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
-
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
-
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
-
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
-
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
-
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
-
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
-
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
-
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
-
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
-
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
-
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
-
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
-
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
-
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
-
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
-
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
-
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
-
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
-
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
-
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
-
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
-
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
-
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
-
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
-
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
-
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
-
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
-
<a name='L33'></a><a href='#L33'>33</a>
|
|
99
|
-
<a name='L34'></a><a href='#L34'>34</a>
|
|
100
|
-
<a name='L35'></a><a href='#L35'>35</a>
|
|
101
|
-
<a name='L36'></a><a href='#L36'>36</a>
|
|
102
|
-
<a name='L37'></a><a href='#L37'>37</a>
|
|
103
|
-
<a name='L38'></a><a href='#L38'>38</a>
|
|
104
|
-
<a name='L39'></a><a href='#L39'>39</a>
|
|
105
|
-
<a name='L40'></a><a href='#L40'>40</a>
|
|
106
|
-
<a name='L41'></a><a href='#L41'>41</a>
|
|
107
|
-
<a name='L42'></a><a href='#L42'>42</a>
|
|
108
|
-
<a name='L43'></a><a href='#L43'>43</a>
|
|
109
|
-
<a name='L44'></a><a href='#L44'>44</a>
|
|
110
|
-
<a name='L45'></a><a href='#L45'>45</a>
|
|
111
|
-
<a name='L46'></a><a href='#L46'>46</a>
|
|
112
|
-
<a name='L47'></a><a href='#L47'>47</a>
|
|
113
|
-
<a name='L48'></a><a href='#L48'>48</a>
|
|
114
|
-
<a name='L49'></a><a href='#L49'>49</a>
|
|
115
|
-
<a name='L50'></a><a href='#L50'>50</a>
|
|
116
|
-
<a name='L51'></a><a href='#L51'>51</a>
|
|
117
|
-
<a name='L52'></a><a href='#L52'>52</a>
|
|
118
|
-
<a name='L53'></a><a href='#L53'>53</a>
|
|
119
|
-
<a name='L54'></a><a href='#L54'>54</a>
|
|
120
|
-
<a name='L55'></a><a href='#L55'>55</a>
|
|
121
|
-
<a name='L56'></a><a href='#L56'>56</a>
|
|
122
|
-
<a name='L57'></a><a href='#L57'>57</a>
|
|
123
|
-
<a name='L58'></a><a href='#L58'>58</a>
|
|
124
|
-
<a name='L59'></a><a href='#L59'>59</a>
|
|
125
|
-
<a name='L60'></a><a href='#L60'>60</a>
|
|
126
|
-
<a name='L61'></a><a href='#L61'>61</a>
|
|
127
|
-
<a name='L62'></a><a href='#L62'>62</a>
|
|
128
|
-
<a name='L63'></a><a href='#L63'>63</a>
|
|
129
|
-
<a name='L64'></a><a href='#L64'>64</a>
|
|
130
|
-
<a name='L65'></a><a href='#L65'>65</a>
|
|
131
|
-
<a name='L66'></a><a href='#L66'>66</a>
|
|
132
|
-
<a name='L67'></a><a href='#L67'>67</a>
|
|
133
|
-
<a name='L68'></a><a href='#L68'>68</a>
|
|
134
|
-
<a name='L69'></a><a href='#L69'>69</a>
|
|
135
|
-
<a name='L70'></a><a href='#L70'>70</a>
|
|
136
|
-
<a name='L71'></a><a href='#L71'>71</a>
|
|
137
|
-
<a name='L72'></a><a href='#L72'>72</a>
|
|
138
|
-
<a name='L73'></a><a href='#L73'>73</a>
|
|
139
|
-
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
|
-
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
|
-
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
-
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
-
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
-
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
-
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
-
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
-
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
-
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
-
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
-
<a name='L85'></a><a href='#L85'>85</a>
|
|
151
|
-
<a name='L86'></a><a href='#L86'>86</a>
|
|
152
|
-
<a name='L87'></a><a href='#L87'>87</a>
|
|
153
|
-
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
|
-
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
|
-
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
-
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
-
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
-
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
-
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
-
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
-
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
-
<a name='L97'></a><a href='#L97'>97</a>
|
|
163
|
-
<a name='L98'></a><a href='#L98'>98</a>
|
|
164
|
-
<a name='L99'></a><a href='#L99'>99</a>
|
|
165
|
-
<a name='L100'></a><a href='#L100'>100</a>
|
|
166
|
-
<a name='L101'></a><a href='#L101'>101</a>
|
|
167
|
-
<a name='L102'></a><a href='#L102'>102</a>
|
|
168
|
-
<a name='L103'></a><a href='#L103'>103</a>
|
|
169
|
-
<a name='L104'></a><a href='#L104'>104</a>
|
|
170
|
-
<a name='L105'></a><a href='#L105'>105</a>
|
|
171
|
-
<a name='L106'></a><a href='#L106'>106</a>
|
|
172
|
-
<a name='L107'></a><a href='#L107'>107</a>
|
|
173
|
-
<a name='L108'></a><a href='#L108'>108</a>
|
|
174
|
-
<a name='L109'></a><a href='#L109'>109</a>
|
|
175
|
-
<a name='L110'></a><a href='#L110'>110</a>
|
|
176
|
-
<a name='L111'></a><a href='#L111'>111</a>
|
|
177
|
-
<a name='L112'></a><a href='#L112'>112</a>
|
|
178
|
-
<a name='L113'></a><a href='#L113'>113</a>
|
|
179
|
-
<a name='L114'></a><a href='#L114'>114</a>
|
|
180
|
-
<a name='L115'></a><a href='#L115'>115</a>
|
|
181
|
-
<a name='L116'></a><a href='#L116'>116</a>
|
|
182
|
-
<a name='L117'></a><a href='#L117'>117</a>
|
|
183
|
-
<a name='L118'></a><a href='#L118'>118</a>
|
|
184
|
-
<a name='L119'></a><a href='#L119'>119</a>
|
|
185
|
-
<a name='L120'></a><a href='#L120'>120</a>
|
|
186
|
-
<a name='L121'></a><a href='#L121'>121</a>
|
|
187
|
-
<a name='L122'></a><a href='#L122'>122</a>
|
|
188
|
-
<a name='L123'></a><a href='#L123'>123</a>
|
|
189
|
-
<a name='L124'></a><a href='#L124'>124</a>
|
|
190
|
-
<a name='L125'></a><a href='#L125'>125</a>
|
|
191
|
-
<a name='L126'></a><a href='#L126'>126</a>
|
|
192
|
-
<a name='L127'></a><a href='#L127'>127</a>
|
|
193
|
-
<a name='L128'></a><a href='#L128'>128</a>
|
|
194
|
-
<a name='L129'></a><a href='#L129'>129</a>
|
|
195
|
-
<a name='L130'></a><a href='#L130'>130</a>
|
|
196
|
-
<a name='L131'></a><a href='#L131'>131</a>
|
|
197
|
-
<a name='L132'></a><a href='#L132'>132</a>
|
|
198
|
-
<a name='L133'></a><a href='#L133'>133</a>
|
|
199
|
-
<a name='L134'></a><a href='#L134'>134</a>
|
|
200
|
-
<a name='L135'></a><a href='#L135'>135</a>
|
|
201
|
-
<a name='L136'></a><a href='#L136'>136</a>
|
|
202
|
-
<a name='L137'></a><a href='#L137'>137</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
203
|
-
<span class="cline-any cline-yes">1x</span>
|
|
204
|
-
<span class="cline-any cline-yes">1x</span>
|
|
205
|
-
<span class="cline-any cline-yes">1x</span>
|
|
206
|
-
<span class="cline-any cline-yes">1x</span>
|
|
207
|
-
<span class="cline-any cline-yes">1x</span>
|
|
208
|
-
<span class="cline-any cline-yes">1x</span>
|
|
209
|
-
<span class="cline-any cline-yes">1x</span>
|
|
210
|
-
<span class="cline-any cline-neutral"> </span>
|
|
211
|
-
<span class="cline-any cline-neutral"> </span>
|
|
212
|
-
<span class="cline-any cline-yes">13x</span>
|
|
213
|
-
<span class="cline-any cline-yes">4x</span>
|
|
214
|
-
<span class="cline-any cline-neutral"> </span>
|
|
215
|
-
<span class="cline-any cline-neutral"> </span>
|
|
216
|
-
<span class="cline-any cline-yes">4x</span>
|
|
217
|
-
<span class="cline-any cline-neutral"> </span>
|
|
218
|
-
<span class="cline-any cline-neutral"> </span>
|
|
219
|
-
<span class="cline-any cline-no"> </span>
|
|
220
|
-
<span class="cline-any cline-neutral"> </span>
|
|
221
|
-
<span class="cline-any cline-yes">9x</span>
|
|
222
|
-
<span class="cline-any cline-yes">21x</span>
|
|
223
|
-
<span class="cline-any cline-neutral"> </span>
|
|
224
|
-
<span class="cline-any cline-yes">22x</span>
|
|
225
|
-
<span class="cline-any cline-neutral"> </span>
|
|
226
|
-
<span class="cline-any cline-neutral"> </span>
|
|
227
|
-
<span class="cline-any cline-neutral"> </span>
|
|
228
|
-
<span class="cline-any cline-neutral"> </span>
|
|
229
|
-
<span class="cline-any cline-neutral"> </span>
|
|
230
|
-
<span class="cline-any cline-neutral"> </span>
|
|
231
|
-
<span class="cline-any cline-yes">13x</span>
|
|
232
|
-
<span class="cline-any cline-yes">4x</span>
|
|
233
|
-
<span class="cline-any cline-neutral"> </span>
|
|
234
|
-
<span class="cline-any cline-yes">9x</span>
|
|
235
|
-
<span class="cline-any cline-yes">9x</span>
|
|
236
|
-
<span class="cline-any cline-neutral"> </span>
|
|
237
|
-
<span class="cline-any cline-neutral"> </span>
|
|
238
|
-
<span class="cline-any cline-neutral"> </span>
|
|
239
|
-
<span class="cline-any cline-yes">13x</span>
|
|
240
|
-
<span class="cline-any cline-yes">4x</span>
|
|
241
|
-
<span class="cline-any cline-neutral"> </span>
|
|
242
|
-
<span class="cline-any cline-yes">9x</span>
|
|
243
|
-
<span class="cline-any cline-yes">9x</span>
|
|
244
|
-
<span class="cline-any cline-neutral"> </span>
|
|
245
|
-
<span class="cline-any cline-no"> </span>
|
|
246
|
-
<span class="cline-any cline-neutral"> </span>
|
|
247
|
-
<span class="cline-any cline-neutral"> </span>
|
|
248
|
-
<span class="cline-any cline-neutral"> </span>
|
|
249
|
-
<span class="cline-any cline-neutral"> </span>
|
|
250
|
-
<span class="cline-any cline-neutral"> </span>
|
|
251
|
-
<span class="cline-any cline-neutral"> </span>
|
|
252
|
-
<span class="cline-any cline-neutral"> </span>
|
|
253
|
-
<span class="cline-any cline-neutral"> </span>
|
|
254
|
-
<span class="cline-any cline-yes">13x</span>
|
|
255
|
-
<span class="cline-any cline-neutral"> </span>
|
|
256
|
-
<span class="cline-any cline-yes">13x</span>
|
|
257
|
-
<span class="cline-any cline-yes">13x</span>
|
|
258
|
-
<span class="cline-any cline-yes">13x</span>
|
|
259
|
-
<span class="cline-any cline-yes">13x</span>
|
|
260
|
-
<span class="cline-any cline-neutral"> </span>
|
|
261
|
-
<span class="cline-any cline-neutral"> </span>
|
|
262
|
-
<span class="cline-any cline-neutral"> </span>
|
|
263
|
-
<span class="cline-any cline-neutral"> </span>
|
|
264
|
-
<span class="cline-any cline-neutral"> </span>
|
|
265
|
-
<span class="cline-any cline-neutral"> </span>
|
|
266
|
-
<span class="cline-any cline-neutral"> </span>
|
|
267
|
-
<span class="cline-any cline-yes">13x</span>
|
|
268
|
-
<span class="cline-any cline-no"> </span>
|
|
269
|
-
<span class="cline-any cline-neutral"> </span>
|
|
270
|
-
<span class="cline-any cline-yes">13x</span>
|
|
271
|
-
<span class="cline-any cline-no"> </span>
|
|
272
|
-
<span class="cline-any cline-neutral"> </span>
|
|
273
|
-
<span class="cline-any cline-neutral"> </span>
|
|
274
|
-
<span class="cline-any cline-yes">13x</span>
|
|
275
|
-
<span class="cline-any cline-yes">13x</span>
|
|
276
|
-
<span class="cline-any cline-yes">13x</span>
|
|
277
|
-
<span class="cline-any cline-yes">13x</span>
|
|
278
|
-
<span class="cline-any cline-yes">13x</span>
|
|
279
|
-
<span class="cline-any cline-neutral"> </span>
|
|
280
|
-
<span class="cline-any cline-neutral"> </span>
|
|
281
|
-
<span class="cline-any cline-neutral"> </span>
|
|
282
|
-
<span class="cline-any cline-neutral"> </span>
|
|
283
|
-
<span class="cline-any cline-neutral"> </span>
|
|
284
|
-
<span class="cline-any cline-neutral"> </span>
|
|
285
|
-
<span class="cline-any cline-neutral"> </span>
|
|
286
|
-
<span class="cline-any cline-yes">13x</span>
|
|
287
|
-
<span class="cline-any cline-yes">13x</span>
|
|
288
|
-
<span class="cline-any cline-neutral"> </span>
|
|
289
|
-
<span class="cline-any cline-yes">1x</span>
|
|
290
|
-
<span class="cline-any cline-yes">1x</span>
|
|
291
|
-
<span class="cline-any cline-yes">2x</span>
|
|
292
|
-
<span class="cline-any cline-neutral"> </span>
|
|
293
|
-
<span class="cline-any cline-neutral"> </span>
|
|
294
|
-
<span class="cline-any cline-neutral"> </span>
|
|
295
|
-
<span class="cline-any cline-yes">2x</span>
|
|
296
|
-
<span class="cline-any cline-yes">2x</span>
|
|
297
|
-
<span class="cline-any cline-neutral"> </span>
|
|
298
|
-
<span class="cline-any cline-yes">1x</span>
|
|
299
|
-
<span class="cline-any cline-neutral"> </span>
|
|
300
|
-
<span class="cline-any cline-yes">13x</span>
|
|
301
|
-
<span class="cline-any cline-yes">13x</span>
|
|
302
|
-
<span class="cline-any cline-yes">30x</span>
|
|
303
|
-
<span class="cline-any cline-yes">30x</span>
|
|
304
|
-
<span class="cline-any cline-neutral"> </span>
|
|
305
|
-
<span class="cline-any cline-no"> </span>
|
|
306
|
-
<span class="cline-any cline-neutral"> </span>
|
|
307
|
-
<span class="cline-any cline-yes">30x</span>
|
|
308
|
-
<span class="cline-any cline-yes">30x</span>
|
|
309
|
-
<span class="cline-any cline-neutral"> </span>
|
|
310
|
-
<span class="cline-any cline-neutral"> </span>
|
|
311
|
-
<span class="cline-any cline-yes">30x</span>
|
|
312
|
-
<span class="cline-any cline-yes">30x</span>
|
|
313
|
-
<span class="cline-any cline-yes">26x</span>
|
|
314
|
-
<span class="cline-any cline-yes">26x</span>
|
|
315
|
-
<span class="cline-any cline-neutral"> </span>
|
|
316
|
-
<span class="cline-any cline-neutral"> </span>
|
|
317
|
-
<span class="cline-any cline-neutral"> </span>
|
|
318
|
-
<span class="cline-any cline-neutral"> </span>
|
|
319
|
-
<span class="cline-any cline-neutral"> </span>
|
|
320
|
-
<span class="cline-any cline-yes">30x</span>
|
|
321
|
-
<span class="cline-any cline-neutral"> </span>
|
|
322
|
-
<span class="cline-any cline-neutral"> </span>
|
|
323
|
-
<span class="cline-any cline-yes">13x</span>
|
|
324
|
-
<span class="cline-any cline-yes">13x</span>
|
|
325
|
-
<span class="cline-any cline-yes">28x</span>
|
|
326
|
-
<span class="cline-any cline-no"> </span>
|
|
327
|
-
<span class="cline-any cline-neutral"> </span>
|
|
328
|
-
<span class="cline-any cline-yes">28x</span>
|
|
329
|
-
<span class="cline-any cline-neutral"> </span>
|
|
330
|
-
<span class="cline-any cline-yes">13x</span>
|
|
331
|
-
<span class="cline-any cline-no"> </span>
|
|
332
|
-
<span class="cline-any cline-neutral"> </span>
|
|
333
|
-
<span class="cline-any cline-neutral"> </span>
|
|
334
|
-
<span class="cline-any cline-yes">13x</span>
|
|
335
|
-
<span class="cline-any cline-neutral"> </span>
|
|
336
|
-
<span class="cline-any cline-yes">13x</span>
|
|
337
|
-
<span class="cline-any cline-neutral"> </span>
|
|
338
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">"use strict";
|
|
339
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
340
|
-
exports.detectIfVariationsChanged = detectIfVariationsChanged;
|
|
341
|
-
exports.getRulePercentageDiff = getRulePercentageDiff;
|
|
342
|
-
exports.detectIfRangesChanged = detectIfRangesChanged;
|
|
343
|
-
exports.getTraffic = getTraffic;
|
|
344
|
-
const sdk_1 = require("@featurevisor/sdk");
|
|
345
|
-
const allocator_1 = require("./allocator");
|
|
346
|
-
function detectIfVariationsChanged(yamlVariations, // as exists in latest YAML
|
|
347
|
-
existingFeature) {
|
|
348
|
-
if (!existingFeature || typeof existingFeature.variations === "undefined") {
|
|
349
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (Array.isArray(yamlVariations) && yamlVariations.length > 0) {
|
|
350
|
-
// feature did not previously have any variations,
|
|
351
|
-
// but now variations have been added
|
|
352
|
-
return true;
|
|
353
|
-
}
|
|
354
|
-
// variations didn't exist before, and not even now
|
|
355
|
-
<span class="cstat-no" title="statement not covered" > return false;</span>
|
|
356
|
-
}
|
|
357
|
-
const checkVariations = Array.isArray(yamlVariations)
|
|
358
|
-
? JSON.stringify(yamlVariations.map(({ value, weight }) => ({ value, weight })))
|
|
359
|
-
: <span class="branch-1 cbranch-no" title="branch not covered" >undefined;</span>
|
|
360
|
-
return (JSON.stringify(existingFeature.variations.map(({ value, weight }) => ({
|
|
361
|
-
value,
|
|
362
|
-
weight,
|
|
363
|
-
}))) !== checkVariations);
|
|
364
|
-
}
|
|
365
|
-
function getRulePercentageDiff(trafficPercentage, // 0 to 100k
|
|
366
|
-
existingTrafficRule) {
|
|
367
|
-
if (!existingTrafficRule) {
|
|
368
|
-
return 0;
|
|
369
|
-
}
|
|
370
|
-
const existingPercentage = existingTrafficRule.percentage;
|
|
371
|
-
return trafficPercentage - existingPercentage;
|
|
372
|
-
}
|
|
373
|
-
function detectIfRangesChanged(availableRanges, // as exists in latest YAML
|
|
374
|
-
existingFeature) {
|
|
375
|
-
if (!existingFeature) {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (!existingFeature.ranges) {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
<span class="cstat-no" title="statement not covered" > return JSON.stringify(existingFeature.ranges) !== JSON.stringify(availableRanges);</span>
|
|
382
|
-
}
|
|
383
|
-
function getTraffic(
|
|
384
|
-
// from current YAML
|
|
385
|
-
variations, parsedRules,
|
|
386
|
-
// from previous release
|
|
387
|
-
existingFeature,
|
|
388
|
-
// ranges from group slots
|
|
389
|
-
ranges) {
|
|
390
|
-
const result = [];
|
|
391
|
-
// @NOTE: may be pass from builder directly?
|
|
392
|
-
const availableRanges = ranges && <span class="branch-1 cbranch-no" title="branch not covered" >ranges.length > 0 </span>? <span class="branch-0 cbranch-no" title="branch not covered" >ranges </span>: [[0, sdk_1.MAX_BUCKETED_NUMBER]];
|
|
393
|
-
parsedRules.forEach(function (parsedRule) {
|
|
394
|
-
const rulePercentage = parsedRule.percentage; // 0 - 100
|
|
395
|
-
const traffic = {
|
|
396
|
-
key: parsedRule.key,
|
|
397
|
-
segments: parsedRule.segments,
|
|
398
|
-
percentage: rulePercentage * (sdk_1.MAX_BUCKETED_NUMBER / 100),
|
|
399
|
-
allocation: [],
|
|
400
|
-
variationWeights: parsedRule.variationWeights,
|
|
401
|
-
};
|
|
402
|
-
// overrides
|
|
403
|
-
<span class="missing-if-branch" title="if path not taken" >I</span>if (parsedRule.variables) {
|
|
404
|
-
<span class="cstat-no" title="statement not covered" > traffic.variables = parsedRule.variables;</span>
|
|
405
|
-
}
|
|
406
|
-
<span class="missing-if-branch" title="if path not taken" >I</span>if (parsedRule.variation) {
|
|
407
|
-
<span class="cstat-no" title="statement not covered" > traffic.variation = parsedRule.variation;</span>
|
|
408
|
-
}
|
|
409
|
-
// detect changes
|
|
410
|
-
const variationsChanged = detectIfVariationsChanged(variations, existingFeature);
|
|
411
|
-
const existingTrafficRule = existingFeature?.traffic.find((t) => t.key === parsedRule.key);
|
|
412
|
-
const rulePercentageDiff = getRulePercentageDiff(traffic.percentage, existingTrafficRule);
|
|
413
|
-
const rangesChanged = detectIfRangesChanged(availableRanges, existingFeature);
|
|
414
|
-
const needsRebucketing = !existingTrafficRule || // new rule
|
|
415
|
-
variationsChanged || // variations changed
|
|
416
|
-
rulePercentageDiff < 0 || // percentage decreased
|
|
417
|
-
rangesChanged || // belongs to a group, and group ranges changed
|
|
418
|
-
// @NOTE: this means, if variationWeights is present, it will always rebucket.
|
|
419
|
-
// worth checking if we can maintain consistent bucketing for this use case as well.
|
|
420
|
-
// but this use case is unlikely to hit in practice because it doesn't matter if the feature itself is 100% rolled out.
|
|
421
|
-
traffic.variationWeights; // variation weights overridden
|
|
422
|
-
let updatedAvailableRanges = JSON.parse(JSON.stringify(availableRanges));
|
|
423
|
-
if (existingTrafficRule && existingTrafficRule.allocation && !needsRebucketing) {
|
|
424
|
-
// increase: build on top of existing allocations
|
|
425
|
-
let existingSum = 0;
|
|
426
|
-
traffic.allocation = existingTrafficRule.allocation.map(function ({ variation, range }) {
|
|
427
|
-
const result = {
|
|
428
|
-
variation,
|
|
429
|
-
range: range,
|
|
430
|
-
};
|
|
431
|
-
existingSum += range[1] - range[0];
|
|
432
|
-
return result;
|
|
433
|
-
});
|
|
434
|
-
updatedAvailableRanges = (0, allocator_1.getUpdatedAvailableRangesAfterFilling)(availableRanges, existingSum);
|
|
435
|
-
}
|
|
436
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (Array.isArray(variations)) {
|
|
437
|
-
variations.forEach(function (variation) {
|
|
438
|
-
let weight = variation.weight;
|
|
439
|
-
<span class="missing-if-branch" title="if path not taken" >I</span>if (traffic.variationWeights && <span class="branch-1 cbranch-no" title="branch not covered" >traffic.variationWeights[variation.value])</span> {
|
|
440
|
-
// override weight from rule
|
|
441
|
-
<span class="cstat-no" title="statement not covered" > weight = traffic.variationWeights[variation.value];</span>
|
|
442
|
-
}
|
|
443
|
-
const percentage = weight * (sdk_1.MAX_BUCKETED_NUMBER / 100);
|
|
444
|
-
const toFillValue = needsRebucketing
|
|
445
|
-
? percentage * (rulePercentage / 100) // whole value
|
|
446
|
-
: (weight / 100) * rulePercentageDiff; // incrementing
|
|
447
|
-
const rangesToFill = (0, allocator_1.getAllocation)(updatedAvailableRanges, toFillValue);
|
|
448
|
-
rangesToFill.forEach(function (range) {
|
|
449
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (traffic.allocation) {
|
|
450
|
-
traffic.allocation.push({
|
|
451
|
-
variation: variation.value,
|
|
452
|
-
range,
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
updatedAvailableRanges = (0, allocator_1.getUpdatedAvailableRangesAfterFilling)(updatedAvailableRanges, toFillValue);
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (traffic.allocation) {
|
|
460
|
-
traffic.allocation = traffic.allocation.filter((a) => {
|
|
461
|
-
<span class="missing-if-branch" title="if path not taken" >I</span>if (a.range && a.range[0] === a.range[1]) {
|
|
462
|
-
<span class="cstat-no" title="statement not covered" > return false;</span>
|
|
463
|
-
}
|
|
464
|
-
return true;
|
|
465
|
-
});
|
|
466
|
-
<span class="missing-if-branch" title="if path not taken" >I</span>if (traffic.allocation.length === 0) {
|
|
467
|
-
<span class="cstat-no" title="statement not covered" > delete traffic.allocation;</span>
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
result.push(traffic);
|
|
471
|
-
});
|
|
472
|
-
return result;
|
|
473
|
-
}
|
|
474
|
-
//# sourceMappingURL=traffic.js.map</pre></td></tr></table></pre>
|
|
475
|
-
|
|
476
|
-
<div class='push'></div><!-- for sticky footer -->
|
|
477
|
-
</div><!-- /wrapper -->
|
|
478
|
-
<div class='footer quiet pad2 space-top1 center small'>
|
|
479
|
-
Code coverage generated by
|
|
480
|
-
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
481
|
-
at 2026-02-05T22:45:36.569Z
|
|
482
|
-
</div>
|
|
483
|
-
<script src="../../prettify.js"></script>
|
|
484
|
-
<script>
|
|
485
|
-
window.onload = function () {
|
|
486
|
-
prettyPrint();
|
|
487
|
-
};
|
|
488
|
-
</script>
|
|
489
|
-
<script src="../../sorter.js"></script>
|
|
490
|
-
<script src="../../block-navigation.js"></script>
|
|
491
|
-
</body>
|
|
492
|
-
</html>
|
|
493
|
-
|