@testgorilla/tgo-typing-test 0.0.1 → 1.0.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.
Files changed (134) hide show
  1. package/esm2022/index.mjs +3 -0
  2. package/esm2022/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.mjs +45 -0
  3. package/esm2022/lib/components/tgo-typing-test/tgo-typing-test.component.mjs +299 -0
  4. package/esm2022/lib/helpers/config.mjs +24 -0
  5. package/esm2022/lib/helpers/constants/default-config.mjs +103 -0
  6. package/esm2022/lib/helpers/controllers/input-controller.mjs +586 -0
  7. package/esm2022/lib/helpers/controllers/quotes-controller.mjs +118 -0
  8. package/esm2022/lib/helpers/observables/config-event.mjs +16 -0
  9. package/esm2022/lib/helpers/observables/timer-event.mjs +16 -0
  10. package/esm2022/lib/helpers/states/active-page.mjs +8 -0
  11. package/esm2022/lib/helpers/states/composition.mjs +20 -0
  12. package/esm2022/lib/helpers/states/page-transition.mjs +8 -0
  13. package/esm2022/lib/helpers/states/slow-timer.mjs +15 -0
  14. package/esm2022/lib/helpers/states/test-active.mjs +8 -0
  15. package/esm2022/lib/helpers/states/time.mjs +11 -0
  16. package/esm2022/lib/helpers/test/caps-warning.mjs +50 -0
  17. package/esm2022/lib/helpers/test/caret.mjs +80 -0
  18. package/esm2022/lib/helpers/test/custom-text.mjs +59 -0
  19. package/esm2022/lib/helpers/test/english-punctuation.mjs +29 -0
  20. package/esm2022/lib/helpers/test/focus.mjs +35 -0
  21. package/esm2022/lib/helpers/test/manual-restart-tracker.mjs +11 -0
  22. package/esm2022/lib/helpers/test/out-of-focus.mjs +14 -0
  23. package/esm2022/lib/helpers/test/replay.mjs +217 -0
  24. package/esm2022/lib/helpers/test/test-input.mjs +264 -0
  25. package/esm2022/lib/helpers/test/test-logic.mjs +927 -0
  26. package/esm2022/lib/helpers/test/test-state.mjs +13 -0
  27. package/esm2022/lib/helpers/test/test-stats.mjs +342 -0
  28. package/esm2022/lib/helpers/test/test-timer.mjs +207 -0
  29. package/esm2022/lib/helpers/test/test-ui.mjs +341 -0
  30. package/esm2022/lib/helpers/test/test-words.mjs +69 -0
  31. package/esm2022/lib/helpers/test/timer-progress.mjs +15 -0
  32. package/esm2022/lib/helpers/test/weak-spot.mjs +65 -0
  33. package/esm2022/lib/helpers/test/wordset.mjs +100 -0
  34. package/esm2022/lib/utils/misc.mjs +673 -0
  35. package/esm2022/testgorilla-tgo-typing-test.mjs +5 -0
  36. package/fesm2022/testgorilla-tgo-typing-test.mjs +4707 -0
  37. package/fesm2022/testgorilla-tgo-typing-test.mjs.map +1 -0
  38. package/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.d.ts +14 -0
  39. package/lib/components/tgo-typing-test/tgo-typing-test.component.d.ts +54 -0
  40. package/lib/helpers/config.d.ts +98 -0
  41. package/lib/helpers/constants/default-config.d.ts +3 -0
  42. package/lib/helpers/controllers/input-controller.d.ts +16 -0
  43. package/lib/helpers/controllers/quotes-controller.d.ts +20 -0
  44. package/lib/helpers/observables/config-event.d.ts +5 -0
  45. package/lib/helpers/observables/timer-event.d.ts +4 -0
  46. package/lib/helpers/states/active-page.d.ts +2 -0
  47. package/lib/helpers/states/composition.d.ts +10 -0
  48. package/lib/helpers/states/page-transition.d.ts +2 -0
  49. package/lib/helpers/states/slow-timer.d.ts +3 -0
  50. package/lib/helpers/states/test-active.d.ts +2 -0
  51. package/lib/helpers/states/time.d.ts +3 -0
  52. package/lib/helpers/test/caps-warning.d.ts +5 -0
  53. package/lib/helpers/test/caret.d.ts +11 -0
  54. package/lib/helpers/test/custom-text.d.ts +16 -0
  55. package/lib/helpers/test/english-punctuation.d.ts +3 -0
  56. package/lib/helpers/test/focus.d.ts +7 -0
  57. package/lib/helpers/test/manual-restart-tracker.d.ts +3 -0
  58. package/lib/helpers/test/out-of-focus.d.ts +4 -0
  59. package/lib/helpers/test/replay.d.ts +20 -0
  60. package/lib/helpers/test/test-input.d.ts +86 -0
  61. package/lib/helpers/test/test-logic.d.ts +25 -0
  62. package/lib/helpers/test/test-state.d.ts +7 -0
  63. package/lib/helpers/test/test-stats.d.ts +92 -0
  64. package/lib/helpers/test/test-timer.d.ts +6 -0
  65. package/lib/helpers/test/test-ui.d.ts +27 -0
  66. package/lib/helpers/test/test-words.d.ts +23 -0
  67. package/lib/helpers/test/timer-progress.d.ts +3 -0
  68. package/lib/helpers/test/weak-spot.d.ts +3 -0
  69. package/lib/helpers/test/wordset.d.ts +7 -0
  70. package/lib/utils/misc.d.ts +81 -0
  71. package/package.json +18 -7
  72. package/.eslintrc.json +0 -45
  73. package/jest.config.ts +0 -21
  74. package/ng-package.json +0 -15
  75. package/project.json +0 -36
  76. package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.html +0 -30
  77. package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.spec.ts +0 -250
  78. package/src/lib/components/tgo-typing-replay-input/tgo-typing-replay-input.component.ts +0 -48
  79. package/src/lib/components/tgo-typing-test/tgo-typing-test.component.html +0 -72
  80. package/src/lib/components/tgo-typing-test/tgo-typing-test.component.spec.ts +0 -699
  81. package/src/lib/components/tgo-typing-test/tgo-typing-test.component.ts +0 -294
  82. package/src/lib/helpers/config.ts +0 -28
  83. package/src/lib/helpers/constants/default-config.ts +0 -103
  84. package/src/lib/helpers/controllers/input-controller.ts +0 -710
  85. package/src/lib/helpers/controllers/quotes-controller.ts +0 -183
  86. package/src/lib/helpers/observables/banner-event.ts +0 -18
  87. package/src/lib/helpers/observables/config-event.ts +0 -31
  88. package/src/lib/helpers/observables/timer-event.ts +0 -18
  89. package/src/lib/helpers/states/active-page.ts +0 -9
  90. package/src/lib/helpers/states/composition.ts +0 -29
  91. package/src/lib/helpers/states/page-transition.ts +0 -9
  92. package/src/lib/helpers/states/slow-timer.ts +0 -16
  93. package/src/lib/helpers/states/test-active.ts +0 -9
  94. package/src/lib/helpers/states/time.ts +0 -13
  95. package/src/lib/helpers/test/caps-warning.ts +0 -50
  96. package/src/lib/helpers/test/caret.ts +0 -92
  97. package/src/lib/helpers/test/custom-text.ts +0 -73
  98. package/src/lib/helpers/test/english-punctuation.ts +0 -38
  99. package/src/lib/helpers/test/focus.ts +0 -39
  100. package/src/lib/helpers/test/manual-restart-tracker.ts +0 -13
  101. package/src/lib/helpers/test/out-of-focus.ts +0 -19
  102. package/src/lib/helpers/test/replay.ts +0 -265
  103. package/src/lib/helpers/test/test-input.ts +0 -320
  104. package/src/lib/helpers/test/test-logic.ts +0 -1039
  105. package/src/lib/helpers/test/test-state.ts +0 -17
  106. package/src/lib/helpers/test/test-stats.ts +0 -442
  107. package/src/lib/helpers/test/test-timer.ts +0 -209
  108. package/src/lib/helpers/test/test-ui.ts +0 -370
  109. package/src/lib/helpers/test/test-words.ts +0 -72
  110. package/src/lib/helpers/test/timer-progress.ts +0 -16
  111. package/src/lib/helpers/test/tts.ts +0 -42
  112. package/src/lib/helpers/test/weak-spot.ts +0 -74
  113. package/src/lib/helpers/test/wordset.ts +0 -109
  114. package/src/lib/styles/animations.scss +0 -101
  115. package/src/lib/styles/caret.scss +0 -108
  116. package/src/lib/styles/core.scss +0 -498
  117. package/src/lib/styles/index.scss +0 -19
  118. package/src/lib/styles/inputs.scss +0 -290
  119. package/src/lib/styles/popups.scss +0 -1311
  120. package/src/lib/styles/test.scss +0 -1008
  121. package/src/lib/styles/z_media-queries.scss +0 -848
  122. package/src/lib/types/types.d.ts +0 -731
  123. package/src/lib/utils/misc.ts +0 -776
  124. package/src/test-setup.ts +0 -1
  125. package/tsconfig.json +0 -16
  126. package/tsconfig.lib.json +0 -14
  127. package/tsconfig.lib.prod.json +0 -9
  128. package/tsconfig.spec.json +0 -11
  129. /package/{src/assets → assets}/typing-test-languages/english.json +0 -0
  130. /package/{src/assets → assets}/typing-test-languages/english_punctuation.json +0 -0
  131. /package/{src/assets → assets}/typing-test-languages/quotes/english_version_1.json +0 -0
  132. /package/{src/assets → assets}/typing-test-languages/quotes/english_version_2.json +0 -0
  133. /package/{src/assets → assets}/typing-test-languages/quotes/filtered_sources.json +0 -0
  134. /package/{src/index.ts → index.d.ts} +0 -0
@@ -0,0 +1,13 @@
1
+ export let isRepeated = false;
2
+ export let isPaceRepeat = false;
3
+ export let activeChallenge = null;
4
+ export function setRepeated(tf) {
5
+ isRepeated = tf;
6
+ }
7
+ export function setPaceRepeat(tf) {
8
+ isPaceRepeat = tf;
9
+ }
10
+ export function setActiveChallenge(val) {
11
+ activeChallenge = val;
12
+ }
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1zdGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL3Rnby10eXBpbmctdGVzdC9zcmMvbGliL2hlbHBlcnMvdGVzdC90ZXN0LXN0YXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE1BQU0sQ0FBQyxJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7QUFDOUIsTUFBTSxDQUFDLElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQztBQUNoQyxNQUFNLENBQUMsSUFBSSxlQUFlLEdBQWlDLElBQUksQ0FBQztBQUVoRSxNQUFNLFVBQVUsV0FBVyxDQUFDLEVBQVc7SUFDckMsVUFBVSxHQUFHLEVBQUUsQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxVQUFVLGFBQWEsQ0FBQyxFQUFXO0lBQ3ZDLFlBQVksR0FBRyxFQUFFLENBQUM7QUFDcEIsQ0FBQztBQUVELE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxHQUFpQztJQUNsRSxlQUFlLEdBQUcsR0FBRyxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNb25rZXlUeXBlcyB9IGZyb20gJy4uLy4uL3R5cGVzL3R5cGVzJztcblxuZXhwb3J0IGxldCBpc1JlcGVhdGVkID0gZmFsc2U7XG5leHBvcnQgbGV0IGlzUGFjZVJlcGVhdCA9IGZhbHNlO1xuZXhwb3J0IGxldCBhY3RpdmVDaGFsbGVuZ2U6IG51bGwgfCBNb25rZXlUeXBlcy5DaGFsbGVuZ2UgPSBudWxsO1xuXG5leHBvcnQgZnVuY3Rpb24gc2V0UmVwZWF0ZWQodGY6IGJvb2xlYW4pOiB2b2lkIHtcbiAgaXNSZXBlYXRlZCA9IHRmO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0UGFjZVJlcGVhdCh0ZjogYm9vbGVhbik6IHZvaWQge1xuICBpc1BhY2VSZXBlYXQgPSB0Zjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldEFjdGl2ZUNoYWxsZW5nZSh2YWw6IG51bGwgfCBNb25rZXlUeXBlcy5DaGFsbGVuZ2UpOiB2b2lkIHtcbiAgYWN0aXZlQ2hhbGxlbmdlID0gdmFsO1xufVxuIl19
@@ -0,0 +1,342 @@
1
+ import Config from '../../helpers/config';
2
+ import * as Misc from '../../utils/misc';
3
+ import * as TestInput from './test-input';
4
+ import * as TestWords from './test-words';
5
+ export let invalid = false;
6
+ export let start, end;
7
+ export let start2, end2;
8
+ export let lastSecondNotRound = false;
9
+ export let lastTestWpm = 0;
10
+ export function setLastTestWpm(wpm) {
11
+ lastTestWpm = wpm;
12
+ }
13
+ export let lastResult;
14
+ export function setLastResult(result) {
15
+ lastResult = result;
16
+ }
17
+ let wpmCalcDebug = false;
18
+ export function wpmCalculationDebug() {
19
+ console.log('wpm calculation debug enabled');
20
+ wpmCalcDebug = true;
21
+ }
22
+ export function getStats() {
23
+ const ret = {
24
+ lastResult,
25
+ start,
26
+ end,
27
+ wpmHistory: TestInput.wpmHistory,
28
+ rawHistory: TestInput.wpmHistory,
29
+ burstHistory: TestInput.burstHistory,
30
+ keypressPerSecond: TestInput.keypressPerSecond,
31
+ currentKeypress: TestInput.currentKeypress,
32
+ lastKeypress: TestInput.lastKeypress,
33
+ currentBurstStart: TestInput.currentBurstStart,
34
+ lastSecondNotRound,
35
+ missedWords: TestInput.missedWords,
36
+ accuracy: TestInput.accuracy,
37
+ keypressTimings: TestInput.keypressTimings,
38
+ };
39
+ try {
40
+ ret.keySpacingStats = {
41
+ average: TestInput.keypressTimings.spacing.array.reduce((previous, current) => (current += previous)) / TestInput.keypressTimings.spacing.array.length,
42
+ sd: Misc.stdDev(TestInput.keypressTimings.spacing.array),
43
+ };
44
+ }
45
+ catch (e) {
46
+ //
47
+ }
48
+ try {
49
+ ret.keyDurationStats = {
50
+ average: TestInput.keypressTimings.duration.array.reduce((previous, current) => (current += previous)) / TestInput.keypressTimings.duration.array.length,
51
+ sd: Misc.stdDev(TestInput.keypressTimings.duration.array),
52
+ };
53
+ }
54
+ catch (e) {
55
+ //
56
+ }
57
+ return ret;
58
+ }
59
+ export function restart() {
60
+ start = 0;
61
+ end = 0;
62
+ invalid = false;
63
+ lastSecondNotRound = false;
64
+ }
65
+ export let restartCount = 0;
66
+ export let incompleteSeconds = 0;
67
+ export function incrementRestartCount() {
68
+ restartCount++;
69
+ }
70
+ export function incrementIncompleteSeconds(val) {
71
+ incompleteSeconds += val;
72
+ }
73
+ export function resetIncomplete() {
74
+ restartCount = 0;
75
+ incompleteSeconds = 0;
76
+ }
77
+ export function setInvalid() {
78
+ invalid = true;
79
+ }
80
+ export function calculateTestSeconds(now) {
81
+ if (now === undefined) {
82
+ const endAfkSeconds = (end - TestInput.lastKeypress) / 1000;
83
+ if ((Config.mode == 'zen' || TestInput.bailout) && endAfkSeconds < 7) {
84
+ return (TestInput.lastKeypress - start) / 1000;
85
+ }
86
+ else {
87
+ return (end - start) / 1000;
88
+ }
89
+ }
90
+ else {
91
+ return (now - start) / 1000;
92
+ }
93
+ }
94
+ export function calculateWpmAndRaw() {
95
+ let chars = 0;
96
+ let correctWordChars = 0;
97
+ let spaces = 0;
98
+ //check input history
99
+ for (let i = 0; i < TestInput.input.history.length; i++) {
100
+ const word = Config.mode == 'zen' ? TestInput.input.getHistory(i) : TestWords.words.get(i);
101
+ if (TestInput.input.getHistory(i) == word) {
102
+ //the word is correct
103
+ //+1 for space
104
+ correctWordChars += word.length;
105
+ if (i < TestInput.input.history.length - 1 &&
106
+ Misc.getLastChar(TestInput.input.getHistory(i)) !== '\n') {
107
+ spaces++;
108
+ }
109
+ }
110
+ chars += TestInput.input.getHistory(i).length;
111
+ }
112
+ if (TestInput.input.current !== '') {
113
+ const word = Config.mode == 'zen' ? TestInput.input.current : TestWords.words.getCurrent();
114
+ //check whats currently typed
115
+ const toAdd = {
116
+ correct: 0,
117
+ incorrect: 0,
118
+ missed: 0,
119
+ };
120
+ for (let c = 0; c < word.length; c++) {
121
+ if (c < TestInput.input.current.length) {
122
+ //on char that still has a word list pair
123
+ if (TestInput.input.current[c] == word[c]) {
124
+ toAdd.correct++;
125
+ }
126
+ else {
127
+ toAdd.incorrect++;
128
+ }
129
+ }
130
+ else {
131
+ //on char that is extra
132
+ toAdd.missed++;
133
+ }
134
+ }
135
+ chars += toAdd.correct;
136
+ chars += toAdd.incorrect;
137
+ chars += toAdd.missed;
138
+ if (toAdd.incorrect == 0) {
139
+ //word is correct so far, add chars
140
+ correctWordChars += toAdd.correct;
141
+ }
142
+ }
143
+ if (Config.funbox === 'nospace' || Config.funbox === 'arrows') {
144
+ spaces = 0;
145
+ }
146
+ chars += TestInput.input.current.length;
147
+ const testSeconds = calculateTestSeconds(performance.now());
148
+ const wpm = Math.round(((correctWordChars + spaces) * (60 / testSeconds)) / 5);
149
+ const raw = Math.round(((chars + spaces) * (60 / testSeconds)) / 5);
150
+ return {
151
+ wpm: wpm,
152
+ raw: raw,
153
+ };
154
+ }
155
+ export function setEnd(e) {
156
+ end = e;
157
+ end2 = Date.now();
158
+ }
159
+ export function setStart(s) {
160
+ start = s;
161
+ start2 = Date.now();
162
+ }
163
+ export function calculateAfkSeconds(testSeconds) {
164
+ let extraAfk = 0;
165
+ if (testSeconds !== undefined) {
166
+ if (Config.mode === 'time') {
167
+ extraAfk = Math.round(testSeconds) - TestInput.keypressPerSecond.length;
168
+ }
169
+ else {
170
+ extraAfk = Math.ceil(testSeconds) - TestInput.keypressPerSecond.length;
171
+ }
172
+ if (extraAfk < 0)
173
+ extraAfk = 0;
174
+ // console.log("-- extra afk debug");
175
+ // console.log("should be " + Math.ceil(testSeconds));
176
+ // console.log(keypressPerSecond.length);
177
+ // console.log(
178
+ // `gonna add extra ${extraAfk} seconds of afk because of no keypress data`
179
+ // );
180
+ }
181
+ const ret = TestInput.keypressPerSecond.filter(x => x.afk).length;
182
+ return ret + extraAfk;
183
+ }
184
+ export function setLastSecondNotRound() {
185
+ lastSecondNotRound = true;
186
+ }
187
+ export function calculateBurst() {
188
+ const timeToWrite = (performance.now() - TestInput.currentBurstStart) / 1000;
189
+ let wordLength;
190
+ wordLength = TestInput.input.current.length;
191
+ if (wordLength == 0) {
192
+ wordLength = TestInput.input.getHistoryLast()?.length ?? 0;
193
+ }
194
+ if (wordLength == 0)
195
+ return 0;
196
+ const speed = Misc.roundTo2((wordLength * (60 / timeToWrite)) / 5);
197
+ return Math.round(speed);
198
+ }
199
+ export function calculateAccuracy() {
200
+ const acc = (TestInput.accuracy.correct / (TestInput.accuracy.correct + TestInput.accuracy.incorrect)) *
201
+ 100;
202
+ return isNaN(acc) ? 0 : acc;
203
+ }
204
+ export function removeAfkData() {
205
+ const testSeconds = calculateTestSeconds();
206
+ TestInput.keypressPerSecond.splice(testSeconds);
207
+ TestInput.wpmHistory.splice(testSeconds);
208
+ TestInput.burstHistory.splice(testSeconds);
209
+ TestInput.rawHistory.splice(testSeconds);
210
+ }
211
+ function countChars() {
212
+ let correctWordChars = 0;
213
+ let correctChars = 0;
214
+ let incorrectChars = 0;
215
+ let extraChars = 0;
216
+ let missedChars = 0;
217
+ let spaces = 0;
218
+ let correctspaces = 0;
219
+ for (let i = 0; i < TestInput.input.history.length; i++) {
220
+ const word = Config.mode == 'zen' ? TestInput.input.getHistory(i) : TestWords.words.get(i);
221
+ if (TestInput.input.getHistory(i) === '') {
222
+ //last word that was not started
223
+ continue;
224
+ }
225
+ if (TestInput.input.getHistory(i) == word) {
226
+ //the word is correct
227
+ correctWordChars += word.length;
228
+ correctChars += word.length;
229
+ if (i < TestInput.input.history.length - 1 &&
230
+ Misc.getLastChar(TestInput.input.getHistory(i)) !== '\n') {
231
+ correctspaces++;
232
+ }
233
+ }
234
+ else if (TestInput.input.getHistory(i).length >= word.length) {
235
+ //too many chars
236
+ for (let c = 0; c < TestInput.input.getHistory(i).length; c++) {
237
+ if (c < word.length) {
238
+ //on char that still has a word list pair
239
+ if (TestInput.input.getHistory(i)[c] == word[c]) {
240
+ correctChars++;
241
+ }
242
+ else {
243
+ incorrectChars++;
244
+ }
245
+ }
246
+ else {
247
+ //on char that is extra
248
+ extraChars++;
249
+ }
250
+ }
251
+ }
252
+ else {
253
+ //not enough chars
254
+ const toAdd = {
255
+ correct: 0,
256
+ incorrect: 0,
257
+ missed: 0,
258
+ };
259
+ for (let c = 0; c < word.length; c++) {
260
+ if (c < TestInput.input.getHistory(i).length) {
261
+ //on char that still has a word list pair
262
+ if (TestInput.input.getHistory(i)[c] == word[c]) {
263
+ toAdd.correct++;
264
+ }
265
+ else {
266
+ toAdd.incorrect++;
267
+ }
268
+ }
269
+ else {
270
+ //on char that is extra
271
+ toAdd.missed++;
272
+ }
273
+ }
274
+ correctChars += toAdd.correct;
275
+ incorrectChars += toAdd.incorrect;
276
+ if (i === TestInput.input.history.length - 1 && Config.mode == 'time') {
277
+ //last word - check if it was all correct - add to correct word chars
278
+ if (toAdd.incorrect === 0)
279
+ correctWordChars += toAdd.correct;
280
+ }
281
+ else {
282
+ missedChars += toAdd.missed;
283
+ }
284
+ }
285
+ if (i < TestInput.input.history.length - 1) {
286
+ spaces++;
287
+ }
288
+ }
289
+ if (Config.funbox === 'nospace' || Config.funbox === 'arrows') {
290
+ spaces = 0;
291
+ correctspaces = 0;
292
+ }
293
+ return {
294
+ spaces: spaces,
295
+ correctWordChars: correctWordChars,
296
+ allCorrectChars: correctChars,
297
+ incorrectChars: Config.mode == 'zen' ? TestInput.accuracy.incorrect : incorrectChars,
298
+ extraChars: extraChars,
299
+ missedChars: missedChars,
300
+ correctSpaces: correctspaces,
301
+ };
302
+ }
303
+ export function calculateStats() {
304
+ let testSeconds = calculateTestSeconds();
305
+ if (wpmCalcDebug) {
306
+ console.log('date based time', (end2 - start2) / 1000);
307
+ console.log('performance.now based time', testSeconds);
308
+ }
309
+ if (Config.mode != 'custom') {
310
+ testSeconds = Misc.roundTo2(testSeconds);
311
+ if (wpmCalcDebug) {
312
+ console.log('mode is not custom - wounding');
313
+ console.log('new time', testSeconds);
314
+ }
315
+ }
316
+ const chars = countChars();
317
+ const wpm = Misc.roundTo2(((chars.correctWordChars + chars.correctSpaces) * (60 / testSeconds)) / 5);
318
+ const wpmraw = Misc.roundTo2(((chars.allCorrectChars + chars.spaces + chars.incorrectChars + chars.extraChars) *
319
+ (60 / testSeconds)) /
320
+ 5);
321
+ if (wpmCalcDebug) {
322
+ console.log('chars', chars);
323
+ console.log('wpm', ((chars.correctWordChars + chars.correctSpaces) * (60 / testSeconds)) / 5);
324
+ console.log('wpm rounded to 2', wpm);
325
+ console.log('wpmraw', wpmraw);
326
+ }
327
+ const acc = Misc.roundTo2(calculateAccuracy());
328
+ return {
329
+ wpm: isNaN(wpm) ? 0 : wpm,
330
+ wpmRaw: isNaN(wpmraw) ? 0 : wpmraw,
331
+ acc: acc,
332
+ correctChars: chars.correctWordChars,
333
+ incorrectChars: chars.incorrectChars,
334
+ missedChars: chars.missedChars,
335
+ extraChars: chars.extraChars,
336
+ allChars: chars.allCorrectChars + chars.spaces + chars.incorrectChars + chars.extraChars,
337
+ time: Misc.roundTo2(testSeconds),
338
+ spaces: chars.spaces,
339
+ correctSpaces: chars.correctSpaces,
340
+ };
341
+ }
342
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1zdGF0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL3Rnby10eXBpbmctdGVzdC9zcmMvbGliL2hlbHBlcnMvdGVzdC90ZXN0LXN0YXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTSxNQUFNLHNCQUFzQixDQUFDO0FBQzFDLE9BQU8sS0FBSyxJQUFJLE1BQU0sa0JBQWtCLENBQUM7QUFDekMsT0FBTyxLQUFLLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDMUMsT0FBTyxLQUFLLFNBQVMsTUFBTSxjQUFjLENBQUM7QUErRTFDLE1BQU0sQ0FBQyxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7QUFDM0IsTUFBTSxDQUFDLElBQUksS0FBYSxFQUFFLEdBQVcsQ0FBQztBQUN0QyxNQUFNLENBQUMsSUFBSSxNQUFjLEVBQUUsSUFBWSxDQUFDO0FBQ3hDLE1BQU0sQ0FBQyxJQUFJLGtCQUFrQixHQUFHLEtBQUssQ0FBQztBQUV0QyxNQUFNLENBQUMsSUFBSSxXQUFXLEdBQUcsQ0FBQyxDQUFDO0FBRTNCLE1BQU0sVUFBVSxjQUFjLENBQUMsR0FBVztJQUN4QyxXQUFXLEdBQUcsR0FBRyxDQUFDO0FBQ3BCLENBQUM7QUFFRCxNQUFNLENBQUMsSUFBSSxVQUFnRCxDQUFDO0FBRTVELE1BQU0sVUFBVSxhQUFhLENBQUMsTUFBNEM7SUFDeEUsVUFBVSxHQUFHLE1BQU0sQ0FBQztBQUN0QixDQUFDO0FBRUQsSUFBSSxZQUFZLEdBQUcsS0FBSyxDQUFDO0FBQ3pCLE1BQU0sVUFBVSxtQkFBbUI7SUFDakMsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBQzdDLFlBQVksR0FBRyxJQUFJLENBQUM7QUFDdEIsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRO0lBQ3RCLE1BQU0sR0FBRyxHQUFlO1FBQ3RCLFVBQVU7UUFDVixLQUFLO1FBQ0wsR0FBRztRQUNILFVBQVUsRUFBRSxTQUFTLENBQUMsVUFBVTtRQUNoQyxVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVU7UUFDaEMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxZQUFZO1FBQ3BDLGlCQUFpQixFQUFFLFNBQVMsQ0FBQyxpQkFBaUI7UUFDOUMsZUFBZSxFQUFFLFNBQVMsQ0FBQyxlQUFlO1FBQzFDLFlBQVksRUFBRSxTQUFTLENBQUMsWUFBWTtRQUNwQyxpQkFBaUIsRUFBRSxTQUFTLENBQUMsaUJBQWlCO1FBQzlDLGtCQUFrQjtRQUNsQixXQUFXLEVBQUUsU0FBUyxDQUFDLFdBQVc7UUFDbEMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLGVBQWUsRUFBRSxTQUFTLENBQUMsZUFBZTtLQUMzQyxDQUFDO0lBRUYsSUFBSSxDQUFDO1FBQ0gsR0FBRyxDQUFDLGVBQWUsR0FBRztZQUNwQixPQUFPLEVBQ0osU0FBUyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsS0FBa0IsQ0FBQyxNQUFNLENBQzFELENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDLENBQzdDLEdBQUcsU0FBUyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU07WUFDcEQsRUFBRSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsS0FBaUIsQ0FBQztTQUNyRSxDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDWCxFQUFFO0lBQ0osQ0FBQztJQUNELElBQUksQ0FBQztRQUNILEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRztZQUNyQixPQUFPLEVBQ0osU0FBUyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBa0IsQ0FBQyxNQUFNLENBQzNELENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDLENBQzdDLEdBQUcsU0FBUyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQU07WUFDckQsRUFBRSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBaUIsQ0FBQztTQUN0RSxDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDWCxFQUFFO0lBQ0osQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELE1BQU0sVUFBVSxPQUFPO0lBQ3JCLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDVixHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBQ1IsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNoQixrQkFBa0IsR0FBRyxLQUFLLENBQUM7QUFDN0IsQ0FBQztBQUVELE1BQU0sQ0FBQyxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7QUFDNUIsTUFBTSxDQUFDLElBQUksaUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0FBRWpDLE1BQU0sVUFBVSxxQkFBcUI7SUFDbkMsWUFBWSxFQUFFLENBQUM7QUFDakIsQ0FBQztBQUVELE1BQU0sVUFBVSwwQkFBMEIsQ0FBQyxHQUFXO0lBQ3BELGlCQUFpQixJQUFJLEdBQUcsQ0FBQztBQUMzQixDQUFDO0FBRUQsTUFBTSxVQUFVLGVBQWU7SUFDN0IsWUFBWSxHQUFHLENBQUMsQ0FBQztJQUNqQixpQkFBaUIsR0FBRyxDQUFDLENBQUM7QUFDeEIsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVO0lBQ3hCLE9BQU8sR0FBRyxJQUFJLENBQUM7QUFDakIsQ0FBQztBQUVELE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxHQUFZO0lBQy9DLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3RCLE1BQU0sYUFBYSxHQUFHLENBQUMsR0FBRyxHQUFHLFNBQVMsQ0FBQyxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUM7UUFDNUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksS0FBSyxJQUFJLFNBQVMsQ0FBQyxPQUFPLENBQUMsSUFBSSxhQUFhLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQ2pELENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxDQUFDLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUM7UUFDOUIsQ0FBQztJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDOUIsQ0FBQztBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsa0JBQWtCO0lBQ2hDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLElBQUksZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNmLHFCQUFxQjtJQUNyQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDeEQsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzRixJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQzFDLHFCQUFxQjtZQUNyQixjQUFjO1lBQ2QsZ0JBQWdCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQztZQUNoQyxJQUNFLENBQUMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQVcsQ0FBQyxLQUFLLElBQUksRUFDbEUsQ0FBQztnQkFDRCxNQUFNLEVBQUUsQ0FBQztZQUNYLENBQUM7UUFDSCxDQUFDO1FBQ0QsS0FBSyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNoRCxDQUFDO0lBQ0QsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDM0YsNkJBQTZCO1FBQzdCLE1BQU0sS0FBSyxHQUFHO1lBQ1osT0FBTyxFQUFFLENBQUM7WUFDVixTQUFTLEVBQUUsQ0FBQztZQUNaLE1BQU0sRUFBRSxDQUFDO1NBQ1YsQ0FBQztRQUNGLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3ZDLHlDQUF5QztnQkFDekMsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztvQkFDMUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNsQixDQUFDO3FCQUFNLENBQUM7b0JBQ04sS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNwQixDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLHVCQUF1QjtnQkFDdkIsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2pCLENBQUM7UUFDSCxDQUFDO1FBQ0QsS0FBSyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDdkIsS0FBSyxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUM7UUFDekIsS0FBSyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDdEIsSUFBSSxLQUFLLENBQUMsU0FBUyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3pCLG1DQUFtQztZQUNuQyxnQkFBZ0IsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLFNBQVMsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlELE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDYixDQUFDO0lBQ0QsS0FBSyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUN4QyxNQUFNLFdBQVcsR0FBRyxvQkFBb0IsQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUM1RCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9FLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLE9BQU87UUFDTCxHQUFHLEVBQUUsR0FBRztRQUNSLEdBQUcsRUFBRSxHQUFHO0tBQ1QsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLFVBQVUsTUFBTSxDQUFDLENBQVM7SUFDOUIsR0FBRyxHQUFHLENBQUMsQ0FBQztJQUNSLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDcEIsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRLENBQUMsQ0FBUztJQUNoQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUN0QixDQUFDO0FBRUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLFdBQW1CO0lBQ3JELElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztJQUNqQixJQUFJLFdBQVcsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM5QixJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDM0IsUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsU0FBUyxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQztRQUMxRSxDQUFDO2FBQU0sQ0FBQztZQUNOLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUM7UUFDekUsQ0FBQztRQUNELElBQUksUUFBUSxHQUFHLENBQUM7WUFBRSxRQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLHFDQUFxQztRQUNyQyxzREFBc0Q7UUFDdEQseUNBQXlDO1FBQ3pDLGVBQWU7UUFDZiw2RUFBNkU7UUFDN0UsS0FBSztJQUNQLENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxTQUFTLENBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNsRSxPQUFPLEdBQUcsR0FBRyxRQUFRLENBQUM7QUFDeEIsQ0FBQztBQUVELE1BQU0sVUFBVSxxQkFBcUI7SUFDbkMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO0FBQzVCLENBQUM7QUFFRCxNQUFNLFVBQVUsY0FBYztJQUM1QixNQUFNLFdBQVcsR0FBRyxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsaUJBQWlCLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDN0UsSUFBSSxVQUFrQixDQUFDO0lBQ3ZCLFVBQVUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDNUMsSUFBSSxVQUFVLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDcEIsVUFBVSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxJQUFJLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsSUFBSSxVQUFVLElBQUksQ0FBQztRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzlCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNuRSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDM0IsQ0FBQztBQUVELE1BQU0sVUFBVSxpQkFBaUI7SUFDL0IsTUFBTSxHQUFHLEdBQ1AsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLE9BQU8sR0FBRyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsT0FBTyxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDMUYsR0FBRyxDQUFDO0lBQ04sT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0FBQzlCLENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYTtJQUMzQixNQUFNLFdBQVcsR0FBRyxvQkFBb0IsRUFBRSxDQUFDO0lBQzNDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDaEQsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDekMsU0FBUyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDM0MsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDM0MsQ0FBQztBQUVELFNBQVMsVUFBVTtJQUNqQixJQUFJLGdCQUFnQixHQUFHLENBQUMsQ0FBQztJQUN6QixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDckIsSUFBSSxjQUFjLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZCLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNuQixJQUFJLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDcEIsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0lBQ3RCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUN4RCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNGLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDekMsZ0NBQWdDO1lBQ2hDLFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUMxQyxxQkFBcUI7WUFDckIsZ0JBQWdCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQztZQUNoQyxZQUFZLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQztZQUM1QixJQUNFLENBQUMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQVcsQ0FBQyxLQUFLLElBQUksRUFDbEUsQ0FBQztnQkFDRCxhQUFhLEVBQUUsQ0FBQztZQUNsQixDQUFDO1FBQ0gsQ0FBQzthQUFNLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUMvRCxnQkFBZ0I7WUFDaEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM5RCxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ3BCLHlDQUF5QztvQkFDekMsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQzt3QkFDaEQsWUFBWSxFQUFFLENBQUM7b0JBQ2pCLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixjQUFjLEVBQUUsQ0FBQztvQkFDbkIsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sdUJBQXVCO29CQUN2QixVQUFVLEVBQUUsQ0FBQztnQkFDZixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7YUFBTSxDQUFDO1lBQ04sa0JBQWtCO1lBQ2xCLE1BQU0sS0FBSyxHQUFHO2dCQUNaLE9BQU8sRUFBRSxDQUFDO2dCQUNWLFNBQVMsRUFBRSxDQUFDO2dCQUNaLE1BQU0sRUFBRSxDQUFDO2FBQ1YsQ0FBQztZQUNGLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUM3Qyx5Q0FBeUM7b0JBQ3pDLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7d0JBQ2hELEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDbEIsQ0FBQzt5QkFBTSxDQUFDO3dCQUNOLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztvQkFDcEIsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sdUJBQXVCO29CQUN2QixLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ2pCLENBQUM7WUFDSCxDQUFDO1lBQ0QsWUFBWSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDOUIsY0FBYyxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUM7WUFDbEMsSUFBSSxDQUFDLEtBQUssU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLE1BQU0sRUFBRSxDQUFDO2dCQUN0RSxxRUFBcUU7Z0JBQ3JFLElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxDQUFDO29CQUFFLGdCQUFnQixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDL0QsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFdBQVcsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDO1lBQzlCLENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFBSSxDQUFDLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzNDLE1BQU0sRUFBRSxDQUFDO1FBQ1gsQ0FBQztJQUNILENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDOUQsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUNYLGFBQWEsR0FBRyxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxNQUFNLEVBQUUsTUFBTTtRQUNkLGdCQUFnQixFQUFFLGdCQUFnQjtRQUNsQyxlQUFlLEVBQUUsWUFBWTtRQUM3QixjQUFjLEVBQUUsTUFBTSxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxjQUFjO1FBQ3BGLFVBQVUsRUFBRSxVQUFVO1FBQ3RCLFdBQVcsRUFBRSxXQUFXO1FBQ3hCLGFBQWEsRUFBRSxhQUFhO0tBQzdCLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxVQUFVLGNBQWM7SUFDNUIsSUFBSSxXQUFXLEdBQUcsb0JBQW9CLEVBQUUsQ0FBQztJQUN6QyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFDdkQsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQzVCLFdBQVcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3pDLElBQUksWUFBWSxFQUFFLENBQUM7WUFDakIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1lBQzdDLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7SUFDSCxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsVUFBVSxFQUFFLENBQUM7SUFDM0IsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FDdkIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsR0FBRyxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQzFFLENBQUM7SUFDRixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUMxQixDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQztRQUMvRSxDQUFDLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztRQUNuQixDQUFDLENBQ0osQ0FBQztJQUNGLElBQUksWUFBWSxFQUFFLENBQUM7UUFDakIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDNUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsR0FBRyxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM5RixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FBQztJQUMvQyxPQUFPO1FBQ0wsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHO1FBQ3pCLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTTtRQUNsQyxHQUFHLEVBQUUsR0FBRztRQUNSLFlBQVksRUFBRSxLQUFLLENBQUMsZ0JBQWdCO1FBQ3BDLGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYztRQUNwQyxXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7UUFDOUIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO1FBQzVCLFFBQVEsRUFBRSxLQUFLLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUMsVUFBVTtRQUN4RixJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFDaEMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1FBQ3BCLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYTtLQUNuQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBDb25maWcgZnJvbSAnLi4vLi4vaGVscGVycy9jb25maWcnO1xuaW1wb3J0ICogYXMgTWlzYyBmcm9tICcuLi8uLi91dGlscy9taXNjJztcbmltcG9ydCAqIGFzIFRlc3RJbnB1dCBmcm9tICcuL3Rlc3QtaW5wdXQnO1xuaW1wb3J0ICogYXMgVGVzdFdvcmRzIGZyb20gJy4vdGVzdC13b3Jkcyc7XG5pbXBvcnQgeyBNb25rZXlUeXBlcyB9IGZyb20gJy4uLy4uL3R5cGVzL3R5cGVzJztcbmludGVyZmFjZSBDaGFyQ291bnQge1xuICBzcGFjZXM6IG51bWJlcjtcbiAgY29ycmVjdFdvcmRDaGFyczogbnVtYmVyO1xuICBhbGxDb3JyZWN0Q2hhcnM6IG51bWJlcjtcbiAgaW5jb3JyZWN0Q2hhcnM6IG51bWJlcjtcbiAgZXh0cmFDaGFyczogbnVtYmVyO1xuICBtaXNzZWRDaGFyczogbnVtYmVyO1xuICBjb3JyZWN0U3BhY2VzOiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBLZXlwcmVzcyB7XG4gIGNvdW50OiBudW1iZXI7XG4gIGVycm9yczogbnVtYmVyO1xuICB3b3JkczogbnVtYmVyW107XG4gIGFmazogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIEtleXByZXNzVGltaW5ncyB7XG4gIHNwYWNpbmc6IHtcbiAgICBjdXJyZW50OiBudW1iZXI7XG4gICAgYXJyYXk6IG51bWJlcltdIHwgJ3Rvb2xvbmcnO1xuICB9O1xuICBkdXJhdGlvbjoge1xuICAgIGN1cnJlbnQ6IG51bWJlcjtcbiAgICBhcnJheTogbnVtYmVyW10gfCAndG9vbG9uZyc7XG4gIH07XG59XG5cbmludGVyZmFjZSBEZWJ1Z1N0YXRzIHtcbiAgbGFzdFJlc3VsdD86IE1vbmtleVR5cGVzLlJlc3VsdDxNb25rZXlUeXBlcy5Nb2RlPjtcbiAgc3RhcnQ6IG51bWJlcjtcbiAgZW5kOiBudW1iZXI7XG4gIHdwbUhpc3Rvcnk6IG51bWJlcltdO1xuICByYXdIaXN0b3J5OiBudW1iZXJbXTtcbiAgYnVyc3RIaXN0b3J5OiBudW1iZXJbXTtcbiAga2V5cHJlc3NQZXJTZWNvbmQ6IEtleXByZXNzW107XG4gIGN1cnJlbnRLZXlwcmVzczoge1xuICAgIGNvdW50OiBudW1iZXI7XG4gICAgZXJyb3JzOiBudW1iZXI7XG4gICAgd29yZHM6IG51bWJlcltdO1xuICAgIGFmazogYm9vbGVhbjtcbiAgfTtcbiAgbGFzdEtleXByZXNzOiBudW1iZXI7XG4gIGN1cnJlbnRCdXJzdFN0YXJ0OiBudW1iZXI7XG4gIGxhc3RTZWNvbmROb3RSb3VuZDogYm9vbGVhbjtcbiAgbWlzc2VkV29yZHM6IHtcbiAgICBbd29yZDogc3RyaW5nXTogbnVtYmVyO1xuICB9O1xuICBhY2N1cmFjeToge1xuICAgIGNvcnJlY3Q6IG51bWJlcjtcbiAgICBpbmNvcnJlY3Q6IG51bWJlcjtcbiAgfTtcbiAga2V5cHJlc3NUaW1pbmdzOiBLZXlwcmVzc1RpbWluZ3M7XG4gIGtleVNwYWNpbmdTdGF0cz86IHtcbiAgICBhdmVyYWdlOiBudW1iZXI7XG4gICAgc2Q6IG51bWJlcjtcbiAgfTtcbiAga2V5RHVyYXRpb25TdGF0cz86IHtcbiAgICBhdmVyYWdlOiBudW1iZXI7XG4gICAgc2Q6IG51bWJlcjtcbiAgfTtcbn1cblxuaW50ZXJmYWNlIFN0YXRzIHtcbiAgd3BtOiBudW1iZXI7XG4gIHdwbVJhdzogbnVtYmVyO1xuICBhY2M6IG51bWJlcjtcbiAgY29ycmVjdENoYXJzOiBudW1iZXI7XG4gIGluY29ycmVjdENoYXJzOiBudW1iZXI7XG4gIG1pc3NlZENoYXJzOiBudW1iZXI7XG4gIGV4dHJhQ2hhcnM6IG51bWJlcjtcbiAgYWxsQ2hhcnM6IG51bWJlcjtcbiAgdGltZTogbnVtYmVyO1xuICBzcGFjZXM6IG51bWJlcjtcbiAgY29ycmVjdFNwYWNlczogbnVtYmVyO1xufVxuXG5leHBvcnQgbGV0IGludmFsaWQgPSBmYWxzZTtcbmV4cG9ydCBsZXQgc3RhcnQ6IG51bWJlciwgZW5kOiBudW1iZXI7XG5leHBvcnQgbGV0IHN0YXJ0MjogbnVtYmVyLCBlbmQyOiBudW1iZXI7XG5leHBvcnQgbGV0IGxhc3RTZWNvbmROb3RSb3VuZCA9IGZhbHNlO1xuXG5leHBvcnQgbGV0IGxhc3RUZXN0V3BtID0gMDtcblxuZXhwb3J0IGZ1bmN0aW9uIHNldExhc3RUZXN0V3BtKHdwbTogbnVtYmVyKTogdm9pZCB7XG4gIGxhc3RUZXN0V3BtID0gd3BtO1xufVxuXG5leHBvcnQgbGV0IGxhc3RSZXN1bHQ6IE1vbmtleVR5cGVzLlJlc3VsdDxNb25rZXlUeXBlcy5Nb2RlPjtcblxuZXhwb3J0IGZ1bmN0aW9uIHNldExhc3RSZXN1bHQocmVzdWx0OiBNb25rZXlUeXBlcy5SZXN1bHQ8TW9ua2V5VHlwZXMuTW9kZT4pOiB2b2lkIHtcbiAgbGFzdFJlc3VsdCA9IHJlc3VsdDtcbn1cblxubGV0IHdwbUNhbGNEZWJ1ZyA9IGZhbHNlO1xuZXhwb3J0IGZ1bmN0aW9uIHdwbUNhbGN1bGF0aW9uRGVidWcoKTogdm9pZCB7XG4gIGNvbnNvbGUubG9nKCd3cG0gY2FsY3VsYXRpb24gZGVidWcgZW5hYmxlZCcpO1xuICB3cG1DYWxjRGVidWcgPSB0cnVlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0U3RhdHMoKTogRGVidWdTdGF0cyB7XG4gIGNvbnN0IHJldDogRGVidWdTdGF0cyA9IHtcbiAgICBsYXN0UmVzdWx0LFxuICAgIHN0YXJ0LFxuICAgIGVuZCxcbiAgICB3cG1IaXN0b3J5OiBUZXN0SW5wdXQud3BtSGlzdG9yeSxcbiAgICByYXdIaXN0b3J5OiBUZXN0SW5wdXQud3BtSGlzdG9yeSxcbiAgICBidXJzdEhpc3Rvcnk6IFRlc3RJbnB1dC5idXJzdEhpc3RvcnksXG4gICAga2V5cHJlc3NQZXJTZWNvbmQ6IFRlc3RJbnB1dC5rZXlwcmVzc1BlclNlY29uZCxcbiAgICBjdXJyZW50S2V5cHJlc3M6IFRlc3RJbnB1dC5jdXJyZW50S2V5cHJlc3MsXG4gICAgbGFzdEtleXByZXNzOiBUZXN0SW5wdXQubGFzdEtleXByZXNzLFxuICAgIGN1cnJlbnRCdXJzdFN0YXJ0OiBUZXN0SW5wdXQuY3VycmVudEJ1cnN0U3RhcnQsXG4gICAgbGFzdFNlY29uZE5vdFJvdW5kLFxuICAgIG1pc3NlZFdvcmRzOiBUZXN0SW5wdXQubWlzc2VkV29yZHMsXG4gICAgYWNjdXJhY3k6IFRlc3RJbnB1dC5hY2N1cmFjeSxcbiAgICBrZXlwcmVzc1RpbWluZ3M6IFRlc3RJbnB1dC5rZXlwcmVzc1RpbWluZ3MsXG4gIH07XG5cbiAgdHJ5IHtcbiAgICByZXQua2V5U3BhY2luZ1N0YXRzID0ge1xuICAgICAgYXZlcmFnZTpcbiAgICAgICAgKFRlc3RJbnB1dC5rZXlwcmVzc1RpbWluZ3Muc3BhY2luZy5hcnJheSBhcyBudW1iZXJbXSkucmVkdWNlKFxuICAgICAgICAgIChwcmV2aW91cywgY3VycmVudCkgPT4gKGN1cnJlbnQgKz0gcHJldmlvdXMpXG4gICAgICAgICkgLyBUZXN0SW5wdXQua2V5cHJlc3NUaW1pbmdzLnNwYWNpbmcuYXJyYXkubGVuZ3RoLFxuICAgICAgc2Q6IE1pc2Muc3RkRGV2KFRlc3RJbnB1dC5rZXlwcmVzc1RpbWluZ3Muc3BhY2luZy5hcnJheSBhcyBudW1iZXJbXSksXG4gICAgfTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIC8vXG4gIH1cbiAgdHJ5IHtcbiAgICByZXQua2V5RHVyYXRpb25TdGF0cyA9IHtcbiAgICAgIGF2ZXJhZ2U6XG4gICAgICAgIChUZXN0SW5wdXQua2V5cHJlc3NUaW1pbmdzLmR1cmF0aW9uLmFycmF5IGFzIG51bWJlcltdKS5yZWR1Y2UoXG4gICAgICAgICAgKHByZXZpb3VzLCBjdXJyZW50KSA9PiAoY3VycmVudCArPSBwcmV2aW91cylcbiAgICAgICAgKSAvIFRlc3RJbnB1dC5rZXlwcmVzc1RpbWluZ3MuZHVyYXRpb24uYXJyYXkubGVuZ3RoLFxuICAgICAgc2Q6IE1pc2Muc3RkRGV2KFRlc3RJbnB1dC5rZXlwcmVzc1RpbWluZ3MuZHVyYXRpb24uYXJyYXkgYXMgbnVtYmVyW10pLFxuICAgIH07XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICAvL1xuICB9XG5cbiAgcmV0dXJuIHJldDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc3RhcnQoKTogdm9pZCB7XG4gIHN0YXJ0ID0gMDtcbiAgZW5kID0gMDtcbiAgaW52YWxpZCA9IGZhbHNlO1xuICBsYXN0U2Vjb25kTm90Um91bmQgPSBmYWxzZTtcbn1cblxuZXhwb3J0IGxldCByZXN0YXJ0Q291bnQgPSAwO1xuZXhwb3J0IGxldCBpbmNvbXBsZXRlU2Vjb25kcyA9IDA7XG5cbmV4cG9ydCBmdW5jdGlvbiBpbmNyZW1lbnRSZXN0YXJ0Q291bnQoKTogdm9pZCB7XG4gIHJlc3RhcnRDb3VudCsrO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaW5jcmVtZW50SW5jb21wbGV0ZVNlY29uZHModmFsOiBudW1iZXIpOiB2b2lkIHtcbiAgaW5jb21wbGV0ZVNlY29uZHMgKz0gdmFsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRJbmNvbXBsZXRlKCk6IHZvaWQge1xuICByZXN0YXJ0Q291bnQgPSAwO1xuICBpbmNvbXBsZXRlU2Vjb25kcyA9IDA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXRJbnZhbGlkKCk6IHZvaWQge1xuICBpbnZhbGlkID0gdHJ1ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZVRlc3RTZWNvbmRzKG5vdz86IG51bWJlcik6IG51bWJlciB7XG4gIGlmIChub3cgPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGVuZEFma1NlY29uZHMgPSAoZW5kIC0gVGVzdElucHV0Lmxhc3RLZXlwcmVzcykgLyAxMDAwO1xuICAgIGlmICgoQ29uZmlnLm1vZGUgPT0gJ3plbicgfHwgVGVzdElucHV0LmJhaWxvdXQpICYmIGVuZEFma1NlY29uZHMgPCA3KSB7XG4gICAgICByZXR1cm4gKFRlc3RJbnB1dC5sYXN0S2V5cHJlc3MgLSBzdGFydCkgLyAxMDAwO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gKGVuZCAtIHN0YXJ0KSAvIDEwMDA7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHJldHVybiAobm93IC0gc3RhcnQpIC8gMTAwMDtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlV3BtQW5kUmF3KCk6IE1vbmtleVR5cGVzLldvcmRzUGVyTWludXRlQW5kUmF3IHtcbiAgbGV0IGNoYXJzID0gMDtcbiAgbGV0IGNvcnJlY3RXb3JkQ2hhcnMgPSAwO1xuICBsZXQgc3BhY2VzID0gMDtcbiAgLy9jaGVjayBpbnB1dCBoaXN0b3J5XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgVGVzdElucHV0LmlucHV0Lmhpc3RvcnkubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCB3b3JkID0gQ29uZmlnLm1vZGUgPT0gJ3plbicgPyBUZXN0SW5wdXQuaW5wdXQuZ2V0SGlzdG9yeShpKSA6IFRlc3RXb3Jkcy53b3Jkcy5nZXQoaSk7XG4gICAgaWYgKFRlc3RJbnB1dC5pbnB1dC5nZXRIaXN0b3J5KGkpID09IHdvcmQpIHtcbiAgICAgIC8vdGhlIHdvcmQgaXMgY29ycmVjdFxuICAgICAgLy8rMSBmb3Igc3BhY2VcbiAgICAgIGNvcnJlY3RXb3JkQ2hhcnMgKz0gd29yZC5sZW5ndGg7XG4gICAgICBpZiAoXG4gICAgICAgIGkgPCBUZXN0SW5wdXQuaW5wdXQuaGlzdG9yeS5sZW5ndGggLSAxICYmXG4gICAgICAgIE1pc2MuZ2V0TGFzdENoYXIoVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSkgYXMgc3RyaW5nKSAhPT0gJ1xcbidcbiAgICAgICkge1xuICAgICAgICBzcGFjZXMrKztcbiAgICAgIH1cbiAgICB9XG4gICAgY2hhcnMgKz0gVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSkubGVuZ3RoO1xuICB9XG4gIGlmIChUZXN0SW5wdXQuaW5wdXQuY3VycmVudCAhPT0gJycpIHtcbiAgICBjb25zdCB3b3JkID0gQ29uZmlnLm1vZGUgPT0gJ3plbicgPyBUZXN0SW5wdXQuaW5wdXQuY3VycmVudCA6IFRlc3RXb3Jkcy53b3Jkcy5nZXRDdXJyZW50KCk7XG4gICAgLy9jaGVjayB3aGF0cyBjdXJyZW50bHkgdHlwZWRcbiAgICBjb25zdCB0b0FkZCA9IHtcbiAgICAgIGNvcnJlY3Q6IDAsXG4gICAgICBpbmNvcnJlY3Q6IDAsXG4gICAgICBtaXNzZWQ6IDAsXG4gICAgfTtcbiAgICBmb3IgKGxldCBjID0gMDsgYyA8IHdvcmQubGVuZ3RoOyBjKyspIHtcbiAgICAgIGlmIChjIDwgVGVzdElucHV0LmlucHV0LmN1cnJlbnQubGVuZ3RoKSB7XG4gICAgICAgIC8vb24gY2hhciB0aGF0IHN0aWxsIGhhcyBhIHdvcmQgbGlzdCBwYWlyXG4gICAgICAgIGlmIChUZXN0SW5wdXQuaW5wdXQuY3VycmVudFtjXSA9PSB3b3JkW2NdKSB7XG4gICAgICAgICAgdG9BZGQuY29ycmVjdCsrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRvQWRkLmluY29ycmVjdCsrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvL29uIGNoYXIgdGhhdCBpcyBleHRyYVxuICAgICAgICB0b0FkZC5taXNzZWQrKztcbiAgICAgIH1cbiAgICB9XG4gICAgY2hhcnMgKz0gdG9BZGQuY29ycmVjdDtcbiAgICBjaGFycyArPSB0b0FkZC5pbmNvcnJlY3Q7XG4gICAgY2hhcnMgKz0gdG9BZGQubWlzc2VkO1xuICAgIGlmICh0b0FkZC5pbmNvcnJlY3QgPT0gMCkge1xuICAgICAgLy93b3JkIGlzIGNvcnJlY3Qgc28gZmFyLCBhZGQgY2hhcnNcbiAgICAgIGNvcnJlY3RXb3JkQ2hhcnMgKz0gdG9BZGQuY29ycmVjdDtcbiAgICB9XG4gIH1cbiAgaWYgKENvbmZpZy5mdW5ib3ggPT09ICdub3NwYWNlJyB8fCBDb25maWcuZnVuYm94ID09PSAnYXJyb3dzJykge1xuICAgIHNwYWNlcyA9IDA7XG4gIH1cbiAgY2hhcnMgKz0gVGVzdElucHV0LmlucHV0LmN1cnJlbnQubGVuZ3RoO1xuICBjb25zdCB0ZXN0U2Vjb25kcyA9IGNhbGN1bGF0ZVRlc3RTZWNvbmRzKHBlcmZvcm1hbmNlLm5vdygpKTtcbiAgY29uc3Qgd3BtID0gTWF0aC5yb3VuZCgoKGNvcnJlY3RXb3JkQ2hhcnMgKyBzcGFjZXMpICogKDYwIC8gdGVzdFNlY29uZHMpKSAvIDUpO1xuICBjb25zdCByYXcgPSBNYXRoLnJvdW5kKCgoY2hhcnMgKyBzcGFjZXMpICogKDYwIC8gdGVzdFNlY29uZHMpKSAvIDUpO1xuICByZXR1cm4ge1xuICAgIHdwbTogd3BtLFxuICAgIHJhdzogcmF3LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0RW5kKGU6IG51bWJlcik6IHZvaWQge1xuICBlbmQgPSBlO1xuICBlbmQyID0gRGF0ZS5ub3coKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldFN0YXJ0KHM6IG51bWJlcik6IHZvaWQge1xuICBzdGFydCA9IHM7XG4gIHN0YXJ0MiA9IERhdGUubm93KCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVBZmtTZWNvbmRzKHRlc3RTZWNvbmRzOiBudW1iZXIpOiBudW1iZXIge1xuICBsZXQgZXh0cmFBZmsgPSAwO1xuICBpZiAodGVzdFNlY29uZHMgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChDb25maWcubW9kZSA9PT0gJ3RpbWUnKSB7XG4gICAgICBleHRyYUFmayA9IE1hdGgucm91bmQodGVzdFNlY29uZHMpIC0gVGVzdElucHV0LmtleXByZXNzUGVyU2Vjb25kLmxlbmd0aDtcbiAgICB9IGVsc2Uge1xuICAgICAgZXh0cmFBZmsgPSBNYXRoLmNlaWwodGVzdFNlY29uZHMpIC0gVGVzdElucHV0LmtleXByZXNzUGVyU2Vjb25kLmxlbmd0aDtcbiAgICB9XG4gICAgaWYgKGV4dHJhQWZrIDwgMCkgZXh0cmFBZmsgPSAwO1xuICAgIC8vIGNvbnNvbGUubG9nKFwiLS0gZXh0cmEgYWZrIGRlYnVnXCIpO1xuICAgIC8vIGNvbnNvbGUubG9nKFwic2hvdWxkIGJlIFwiICsgTWF0aC5jZWlsKHRlc3RTZWNvbmRzKSk7XG4gICAgLy8gY29uc29sZS5sb2coa2V5cHJlc3NQZXJTZWNvbmQubGVuZ3RoKTtcbiAgICAvLyBjb25zb2xlLmxvZyhcbiAgICAvLyAgIGBnb25uYSBhZGQgZXh0cmEgJHtleHRyYUFma30gc2Vjb25kcyBvZiBhZmsgYmVjYXVzZSBvZiBubyBrZXlwcmVzcyBkYXRhYFxuICAgIC8vICk7XG4gIH1cbiAgY29uc3QgcmV0ID0gVGVzdElucHV0LmtleXByZXNzUGVyU2Vjb25kLmZpbHRlcih4ID0+IHguYWZrKS5sZW5ndGg7XG4gIHJldHVybiByZXQgKyBleHRyYUFmaztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldExhc3RTZWNvbmROb3RSb3VuZCgpOiB2b2lkIHtcbiAgbGFzdFNlY29uZE5vdFJvdW5kID0gdHJ1ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZUJ1cnN0KCk6IG51bWJlciB7XG4gIGNvbnN0IHRpbWVUb1dyaXRlID0gKHBlcmZvcm1hbmNlLm5vdygpIC0gVGVzdElucHV0LmN1cnJlbnRCdXJzdFN0YXJ0KSAvIDEwMDA7XG4gIGxldCB3b3JkTGVuZ3RoOiBudW1iZXI7XG4gIHdvcmRMZW5ndGggPSBUZXN0SW5wdXQuaW5wdXQuY3VycmVudC5sZW5ndGg7XG4gIGlmICh3b3JkTGVuZ3RoID09IDApIHtcbiAgICB3b3JkTGVuZ3RoID0gVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnlMYXN0KCk/Lmxlbmd0aCA/PyAwO1xuICB9XG4gIGlmICh3b3JkTGVuZ3RoID09IDApIHJldHVybiAwO1xuICBjb25zdCBzcGVlZCA9IE1pc2Mucm91bmRUbzIoKHdvcmRMZW5ndGggKiAoNjAgLyB0aW1lVG9Xcml0ZSkpIC8gNSk7XG4gIHJldHVybiBNYXRoLnJvdW5kKHNwZWVkKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZUFjY3VyYWN5KCk6IG51bWJlciB7XG4gIGNvbnN0IGFjYyA9XG4gICAgKFRlc3RJbnB1dC5hY2N1cmFjeS5jb3JyZWN0IC8gKFRlc3RJbnB1dC5hY2N1cmFjeS5jb3JyZWN0ICsgVGVzdElucHV0LmFjY3VyYWN5LmluY29ycmVjdCkpICpcbiAgICAxMDA7XG4gIHJldHVybiBpc05hTihhY2MpID8gMCA6IGFjYztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZUFma0RhdGEoKTogdm9pZCB7XG4gIGNvbnN0IHRlc3RTZWNvbmRzID0gY2FsY3VsYXRlVGVzdFNlY29uZHMoKTtcbiAgVGVzdElucHV0LmtleXByZXNzUGVyU2Vjb25kLnNwbGljZSh0ZXN0U2Vjb25kcyk7XG4gIFRlc3RJbnB1dC53cG1IaXN0b3J5LnNwbGljZSh0ZXN0U2Vjb25kcyk7XG4gIFRlc3RJbnB1dC5idXJzdEhpc3Rvcnkuc3BsaWNlKHRlc3RTZWNvbmRzKTtcbiAgVGVzdElucHV0LnJhd0hpc3Rvcnkuc3BsaWNlKHRlc3RTZWNvbmRzKTtcbn1cblxuZnVuY3Rpb24gY291bnRDaGFycygpOiBDaGFyQ291bnQge1xuICBsZXQgY29ycmVjdFdvcmRDaGFycyA9IDA7XG4gIGxldCBjb3JyZWN0Q2hhcnMgPSAwO1xuICBsZXQgaW5jb3JyZWN0Q2hhcnMgPSAwO1xuICBsZXQgZXh0cmFDaGFycyA9IDA7XG4gIGxldCBtaXNzZWRDaGFycyA9IDA7XG4gIGxldCBzcGFjZXMgPSAwO1xuICBsZXQgY29ycmVjdHNwYWNlcyA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgVGVzdElucHV0LmlucHV0Lmhpc3RvcnkubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCB3b3JkID0gQ29uZmlnLm1vZGUgPT0gJ3plbicgPyBUZXN0SW5wdXQuaW5wdXQuZ2V0SGlzdG9yeShpKSA6IFRlc3RXb3Jkcy53b3Jkcy5nZXQoaSk7XG4gICAgaWYgKFRlc3RJbnB1dC5pbnB1dC5nZXRIaXN0b3J5KGkpID09PSAnJykge1xuICAgICAgLy9sYXN0IHdvcmQgdGhhdCB3YXMgbm90IHN0YXJ0ZWRcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAoVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSkgPT0gd29yZCkge1xuICAgICAgLy90aGUgd29yZCBpcyBjb3JyZWN0XG4gICAgICBjb3JyZWN0V29yZENoYXJzICs9IHdvcmQubGVuZ3RoO1xuICAgICAgY29ycmVjdENoYXJzICs9IHdvcmQubGVuZ3RoO1xuICAgICAgaWYgKFxuICAgICAgICBpIDwgVGVzdElucHV0LmlucHV0Lmhpc3RvcnkubGVuZ3RoIC0gMSAmJlxuICAgICAgICBNaXNjLmdldExhc3RDaGFyKFRlc3RJbnB1dC5pbnB1dC5nZXRIaXN0b3J5KGkpIGFzIHN0cmluZykgIT09ICdcXG4nXG4gICAgICApIHtcbiAgICAgICAgY29ycmVjdHNwYWNlcysrO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSkubGVuZ3RoID49IHdvcmQubGVuZ3RoKSB7XG4gICAgICAvL3RvbyBtYW55IGNoYXJzXG4gICAgICBmb3IgKGxldCBjID0gMDsgYyA8IFRlc3RJbnB1dC5pbnB1dC5nZXRIaXN0b3J5KGkpLmxlbmd0aDsgYysrKSB7XG4gICAgICAgIGlmIChjIDwgd29yZC5sZW5ndGgpIHtcbiAgICAgICAgICAvL29uIGNoYXIgdGhhdCBzdGlsbCBoYXMgYSB3b3JkIGxpc3QgcGFpclxuICAgICAgICAgIGlmIChUZXN0SW5wdXQuaW5wdXQuZ2V0SGlzdG9yeShpKVtjXSA9PSB3b3JkW2NdKSB7XG4gICAgICAgICAgICBjb3JyZWN0Q2hhcnMrKztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW5jb3JyZWN0Q2hhcnMrKztcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy9vbiBjaGFyIHRoYXQgaXMgZXh0cmFcbiAgICAgICAgICBleHRyYUNoYXJzKys7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy9ub3QgZW5vdWdoIGNoYXJzXG4gICAgICBjb25zdCB0b0FkZCA9IHtcbiAgICAgICAgY29ycmVjdDogMCxcbiAgICAgICAgaW5jb3JyZWN0OiAwLFxuICAgICAgICBtaXNzZWQ6IDAsXG4gICAgICB9O1xuICAgICAgZm9yIChsZXQgYyA9IDA7IGMgPCB3b3JkLmxlbmd0aDsgYysrKSB7XG4gICAgICAgIGlmIChjIDwgVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSkubGVuZ3RoKSB7XG4gICAgICAgICAgLy9vbiBjaGFyIHRoYXQgc3RpbGwgaGFzIGEgd29yZCBsaXN0IHBhaXJcbiAgICAgICAgICBpZiAoVGVzdElucHV0LmlucHV0LmdldEhpc3RvcnkoaSlbY10gPT0gd29yZFtjXSkge1xuICAgICAgICAgICAgdG9BZGQuY29ycmVjdCsrO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0b0FkZC5pbmNvcnJlY3QrKztcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy9vbiBjaGFyIHRoYXQgaXMgZXh0cmFcbiAgICAgICAgICB0b0FkZC5taXNzZWQrKztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29ycmVjdENoYXJzICs9IHRvQWRkLmNvcnJlY3Q7XG4gICAgICBpbmNvcnJlY3RDaGFycyArPSB0b0FkZC5pbmNvcnJlY3Q7XG4gICAgICBpZiAoaSA9PT0gVGVzdElucHV0LmlucHV0Lmhpc3RvcnkubGVuZ3RoIC0gMSAmJiBDb25maWcubW9kZSA9PSAndGltZScpIHtcbiAgICAgICAgLy9sYXN0IHdvcmQgLSBjaGVjayBpZiBpdCB3YXMgYWxsIGNvcnJlY3QgLSBhZGQgdG8gY29ycmVjdCB3b3JkIGNoYXJzXG4gICAgICAgIGlmICh0b0FkZC5pbmNvcnJlY3QgPT09IDApIGNvcnJlY3RXb3JkQ2hhcnMgKz0gdG9BZGQuY29ycmVjdDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1pc3NlZENoYXJzICs9IHRvQWRkLm1pc3NlZDtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGkgPCBUZXN0SW5wdXQuaW5wdXQuaGlzdG9yeS5sZW5ndGggLSAxKSB7XG4gICAgICBzcGFjZXMrKztcbiAgICB9XG4gIH1cbiAgaWYgKENvbmZpZy5mdW5ib3ggPT09ICdub3NwYWNlJyB8fCBDb25maWcuZnVuYm94ID09PSAnYXJyb3dzJykge1xuICAgIHNwYWNlcyA9IDA7XG4gICAgY29ycmVjdHNwYWNlcyA9IDA7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBzcGFjZXM6IHNwYWNlcyxcbiAgICBjb3JyZWN0V29yZENoYXJzOiBjb3JyZWN0V29yZENoYXJzLFxuICAgIGFsbENvcnJlY3RDaGFyczogY29ycmVjdENoYXJzLFxuICAgIGluY29ycmVjdENoYXJzOiBDb25maWcubW9kZSA9PSAnemVuJyA/IFRlc3RJbnB1dC5hY2N1cmFjeS5pbmNvcnJlY3QgOiBpbmNvcnJlY3RDaGFycyxcbiAgICBleHRyYUNoYXJzOiBleHRyYUNoYXJzLFxuICAgIG1pc3NlZENoYXJzOiBtaXNzZWRDaGFycyxcbiAgICBjb3JyZWN0U3BhY2VzOiBjb3JyZWN0c3BhY2VzLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlU3RhdHMoKTogU3RhdHMge1xuICBsZXQgdGVzdFNlY29uZHMgPSBjYWxjdWxhdGVUZXN0U2Vjb25kcygpO1xuICBpZiAod3BtQ2FsY0RlYnVnKSB7XG4gICAgY29uc29sZS5sb2coJ2RhdGUgYmFzZWQgdGltZScsIChlbmQyIC0gc3RhcnQyKSAvIDEwMDApO1xuICAgIGNvbnNvbGUubG9nKCdwZXJmb3JtYW5jZS5ub3cgYmFzZWQgdGltZScsIHRlc3RTZWNvbmRzKTtcbiAgfVxuICBpZiAoQ29uZmlnLm1vZGUgIT0gJ2N1c3RvbScpIHtcbiAgICB0ZXN0U2Vjb25kcyA9IE1pc2Mucm91bmRUbzIodGVzdFNlY29uZHMpO1xuICAgIGlmICh3cG1DYWxjRGVidWcpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdtb2RlIGlzIG5vdCBjdXN0b20gLSB3b3VuZGluZycpO1xuICAgICAgY29uc29sZS5sb2coJ25ldyB0aW1lJywgdGVzdFNlY29uZHMpO1xuICAgIH1cbiAgfVxuICBjb25zdCBjaGFycyA9IGNvdW50Q2hhcnMoKTtcbiAgY29uc3Qgd3BtID0gTWlzYy5yb3VuZFRvMihcbiAgICAoKGNoYXJzLmNvcnJlY3RXb3JkQ2hhcnMgKyBjaGFycy5jb3JyZWN0U3BhY2VzKSAqICg2MCAvIHRlc3RTZWNvbmRzKSkgLyA1XG4gICk7XG4gIGNvbnN0IHdwbXJhdyA9IE1pc2Mucm91bmRUbzIoXG4gICAgKChjaGFycy5hbGxDb3JyZWN0Q2hhcnMgKyBjaGFycy5zcGFjZXMgKyBjaGFycy5pbmNvcnJlY3RDaGFycyArIGNoYXJzLmV4dHJhQ2hhcnMpICpcbiAgICAgICg2MCAvIHRlc3RTZWNvbmRzKSkgL1xuICAgICAgNVxuICApO1xuICBpZiAod3BtQ2FsY0RlYnVnKSB7XG4gICAgY29uc29sZS5sb2coJ2NoYXJzJywgY2hhcnMpO1xuICAgIGNvbnNvbGUubG9nKCd3cG0nLCAoKGNoYXJzLmNvcnJlY3RXb3JkQ2hhcnMgKyBjaGFycy5jb3JyZWN0U3BhY2VzKSAqICg2MCAvIHRlc3RTZWNvbmRzKSkgLyA1KTtcbiAgICBjb25zb2xlLmxvZygnd3BtIHJvdW5kZWQgdG8gMicsIHdwbSk7XG4gICAgY29uc29sZS5sb2coJ3dwbXJhdycsIHdwbXJhdyk7XG4gIH1cbiAgY29uc3QgYWNjID0gTWlzYy5yb3VuZFRvMihjYWxjdWxhdGVBY2N1cmFjeSgpKTtcbiAgcmV0dXJuIHtcbiAgICB3cG06IGlzTmFOKHdwbSkgPyAwIDogd3BtLFxuICAgIHdwbVJhdzogaXNOYU4od3BtcmF3KSA/IDAgOiB3cG1yYXcsXG4gICAgYWNjOiBhY2MsXG4gICAgY29ycmVjdENoYXJzOiBjaGFycy5jb3JyZWN0V29yZENoYXJzLFxuICAgIGluY29ycmVjdENoYXJzOiBjaGFycy5pbmNvcnJlY3RDaGFycyxcbiAgICBtaXNzZWRDaGFyczogY2hhcnMubWlzc2VkQ2hhcnMsXG4gICAgZXh0cmFDaGFyczogY2hhcnMuZXh0cmFDaGFycyxcbiAgICBhbGxDaGFyczogY2hhcnMuYWxsQ29ycmVjdENoYXJzICsgY2hhcnMuc3BhY2VzICsgY2hhcnMuaW5jb3JyZWN0Q2hhcnMgKyBjaGFycy5leHRyYUNoYXJzLFxuICAgIHRpbWU6IE1pc2Mucm91bmRUbzIodGVzdFNlY29uZHMpLFxuICAgIHNwYWNlczogY2hhcnMuc3BhY2VzLFxuICAgIGNvcnJlY3RTcGFjZXM6IGNoYXJzLmNvcnJlY3RTcGFjZXMsXG4gIH07XG59XG4iXX0=
@@ -0,0 +1,207 @@
1
+ // Most of the code is thanks to
2
+ // https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript
3
+ import Config from '../../helpers/config';
4
+ import * as Misc from '../../utils/misc';
5
+ import * as TimerEvent from '../observables/timer-event';
6
+ import * as SlowTimer from '../states/slow-timer';
7
+ import * as TestActive from '../states/test-active';
8
+ import * as Time from '../states/time';
9
+ import * as Caret from './caret';
10
+ import * as CustomText from './custom-text';
11
+ import * as TestInput from './test-input';
12
+ import * as TestStats from './test-stats';
13
+ import * as TestWords from './test-words';
14
+ import * as TimerProgress from './timer-progress';
15
+ let slowTimerCount = 0;
16
+ let timer = null;
17
+ const interval = 1000;
18
+ let expected = 0;
19
+ let timerDebug = false;
20
+ export function enableTimerDebug() {
21
+ timerDebug = true;
22
+ }
23
+ let checkIfTimeIsUpDisabled = false;
24
+ export function disableCheckIfTimeIsUp() {
25
+ checkIfTimeIsUpDisabled = true;
26
+ }
27
+ export function clear() {
28
+ Time.set(0);
29
+ if (timer !== null)
30
+ clearTimeout(timer);
31
+ }
32
+ function premid() {
33
+ if (timerDebug)
34
+ console.time('premid');
35
+ const premidSecondsLeft = document.querySelector('#premidSecondsLeft');
36
+ if (premidSecondsLeft !== null) {
37
+ premidSecondsLeft.innerHTML = (Config.time - Time.get()).toString();
38
+ }
39
+ if (timerDebug)
40
+ console.timeEnd('premid');
41
+ }
42
+ function updateTimer() {
43
+ if (timerDebug)
44
+ console.time('timer progress update');
45
+ if (Config.mode === 'time' || (Config.mode === 'custom' && CustomText.isTimeRandom)) {
46
+ TimerProgress.update();
47
+ }
48
+ if (timerDebug)
49
+ console.timeEnd('timer progress update');
50
+ }
51
+ function calculateWpmRaw() {
52
+ if (timerDebug)
53
+ console.time('calculate wpm and raw');
54
+ const wpmAndRaw = TestStats.calculateWpmAndRaw();
55
+ if (timerDebug)
56
+ console.timeEnd('calculate wpm and raw');
57
+ if (timerDebug)
58
+ console.time('push to history');
59
+ TestInput.pushToWpmHistory(wpmAndRaw.wpm);
60
+ TestInput.pushToRawHistory(wpmAndRaw.raw);
61
+ if (timerDebug)
62
+ console.timeEnd('push to history');
63
+ return wpmAndRaw;
64
+ }
65
+ function monkey(wpmAndRaw) {
66
+ if (timerDebug)
67
+ console.time('update monkey');
68
+ const num = Config.blindMode ? wpmAndRaw.raw : wpmAndRaw.wpm;
69
+ if (timerDebug)
70
+ console.timeEnd('update monkey');
71
+ }
72
+ function calculateAcc() {
73
+ if (timerDebug)
74
+ console.time('calculate acc');
75
+ const acc = Misc.roundTo2(TestStats.calculateAccuracy());
76
+ if (timerDebug)
77
+ console.timeEnd('calculate acc');
78
+ return acc;
79
+ }
80
+ function layoutfluid() {
81
+ if (timerDebug)
82
+ console.time('layoutfluid');
83
+ if (Config.funbox === 'layoutfluid' && Config.mode === 'time') {
84
+ const layouts = Config.customLayoutfluid
85
+ ? Config.customLayoutfluid.split('#')
86
+ : ['qwerty', 'dvorak', 'colemak'];
87
+ const switchTime = Config.time / layouts.length;
88
+ const time = Time.get();
89
+ const index = Math.floor(time / switchTime);
90
+ const layout = layouts[index];
91
+ const flooredSwitchTimes = [];
92
+ for (let i = 1; i < layouts.length; i++) {
93
+ flooredSwitchTimes.push(Math.floor(switchTime * i));
94
+ }
95
+ }
96
+ if (timerDebug)
97
+ console.timeEnd('layoutfluid');
98
+ }
99
+ function checkIfFailed(wpmAndRaw, acc) {
100
+ if (timerDebug)
101
+ console.time('fail conditions');
102
+ TestInput.pushKeypressesToHistory();
103
+ if (Config.minWpm === 'custom' &&
104
+ wpmAndRaw.wpm < Config.minWpmCustomSpeed &&
105
+ TestWords.words.currentIndex > 3) {
106
+ if (timer !== null)
107
+ clearTimeout(timer);
108
+ SlowTimer.clear();
109
+ slowTimerCount = 0;
110
+ TimerEvent.dispatch('fail', 'min wpm');
111
+ return;
112
+ }
113
+ if (Config.minAcc === 'custom' && acc < Config.minAccCustom) {
114
+ if (timer !== null)
115
+ clearTimeout(timer);
116
+ SlowTimer.clear();
117
+ slowTimerCount = 0;
118
+ TimerEvent.dispatch('fail', 'min accuracy');
119
+ return;
120
+ }
121
+ if (timerDebug)
122
+ console.timeEnd('fail conditions');
123
+ }
124
+ function checkIfTimeIsUp() {
125
+ if (timerDebug)
126
+ console.time('times up check');
127
+ if (Config.mode == 'time' || (Config.mode === 'custom' && CustomText.isTimeRandom)) {
128
+ if ((Time.get() >= Config.time && Config.time !== 0 && Config.mode === 'time') ||
129
+ (Time.get() >= CustomText.time && CustomText.time !== 0 && Config.mode === 'custom')) {
130
+ //times up
131
+ if (timer !== null)
132
+ clearTimeout(timer);
133
+ Caret.hide();
134
+ TestInput.input.pushHistory();
135
+ TestInput.corrected.pushHistory();
136
+ SlowTimer.clear();
137
+ slowTimerCount = 0;
138
+ TimerEvent.dispatch('finish');
139
+ return;
140
+ }
141
+ }
142
+ if (timerDebug)
143
+ console.timeEnd('times up check');
144
+ }
145
+ // ---------------------------------------
146
+ let timerStats = [];
147
+ export function getTimerStats() {
148
+ return timerStats;
149
+ }
150
+ async function timerStep() {
151
+ if (timerDebug)
152
+ console.time('timer step -----------------------------');
153
+ Time.increment();
154
+ premid();
155
+ updateTimer();
156
+ const wpmAndRaw = calculateWpmRaw();
157
+ const acc = calculateAcc();
158
+ monkey(wpmAndRaw);
159
+ layoutfluid();
160
+ checkIfFailed(wpmAndRaw, acc);
161
+ if (!checkIfTimeIsUpDisabled) {
162
+ checkIfTimeIsUp();
163
+ }
164
+ if (timerDebug)
165
+ console.timeEnd('timer step -----------------------------');
166
+ }
167
+ export async function start() {
168
+ SlowTimer.clear();
169
+ slowTimerCount = 0;
170
+ timerStats = [];
171
+ expected = TestStats.start + interval;
172
+ (function loop() {
173
+ const delay = expected - performance.now();
174
+ timerStats.push({
175
+ dateNow: Date.now(),
176
+ now: performance.now(),
177
+ expected: expected,
178
+ nextDelay: delay,
179
+ });
180
+ if ((Config.mode === 'time' && Config.time < 130 && Config.time > 0) ||
181
+ (Config.mode === 'words' && Config.words < 250 && Config.words > 0)) {
182
+ if (delay < interval / 2) {
183
+ //slow timer
184
+ SlowTimer.set();
185
+ }
186
+ if (delay < interval / 10) {
187
+ slowTimerCount++;
188
+ if (slowTimerCount > 5) {
189
+ TimerEvent.dispatch('fail', 'slow timer');
190
+ }
191
+ }
192
+ }
193
+ timer = setTimeout(function () {
194
+ if (!TestActive.get()) {
195
+ if (timer !== null)
196
+ clearTimeout(timer);
197
+ SlowTimer.clear();
198
+ slowTimerCount = 0;
199
+ return;
200
+ }
201
+ timerStep();
202
+ expected += interval;
203
+ loop();
204
+ }, delay);
205
+ })();
206
+ }
207
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC10aW1lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL3Rnby10eXBpbmctdGVzdC9zcmMvbGliL2hlbHBlcnMvdGVzdC90ZXN0LXRpbWVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGdDQUFnQztBQUNoQyw2RkFBNkY7QUFFN0YsT0FBTyxNQUFNLE1BQU0sc0JBQXNCLENBQUM7QUFFMUMsT0FBTyxLQUFLLElBQUksTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEtBQUssVUFBVSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pELE9BQU8sS0FBSyxTQUFTLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxLQUFLLFVBQVUsTUFBTSx1QkFBdUIsQ0FBQztBQUNwRCxPQUFPLEtBQUssSUFBSSxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxLQUFLLE1BQU0sU0FBUyxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxVQUFVLE1BQU0sZUFBZSxDQUFDO0FBQzVDLE9BQU8sS0FBSyxTQUFTLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sS0FBSyxTQUFTLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sS0FBSyxTQUFTLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sS0FBSyxhQUFhLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsSUFBSSxjQUFjLEdBQUcsQ0FBQyxDQUFDO0FBQ3ZCLElBQUksS0FBSyxHQUEwQixJQUFJLENBQUM7QUFDeEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDO0FBQ3RCLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQUVqQixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7QUFDdkIsTUFBTSxVQUFVLGdCQUFnQjtJQUM5QixVQUFVLEdBQUcsSUFBSSxDQUFDO0FBQ3BCLENBQUM7QUFFRCxJQUFJLHVCQUF1QixHQUFHLEtBQUssQ0FBQztBQUNwQyxNQUFNLFVBQVUs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QUFFLENBQUM7Z0JBQ2pCLElBQUksY0FBYyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUN2QixVQUFVLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztnQkFDNUMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBQ0QsS0FBSyxHQUFHLFVBQVUsQ0FBQztZQUNqQixJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7Z0JBQ3RCLElBQUksS0FBSyxLQUFLLElBQUk7b0JBQUUsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN4QyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ2xCLGNBQWMsR0FBRyxDQUFDLENBQUM7Z0JBQ25CLE9BQU87WUFDVCxDQUFDO1lBRUQsU0FBUyxFQUFFLENBQUM7WUFFWixRQUFRLElBQUksUUFBUSxDQUFDO1lBQ3JCLElBQUksRUFBRSxDQUFDO1FBQ1QsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ1osQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUNQLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBNb3N0IG9mIHRoZSBjb2RlIGlzIHRoYW5rcyB0b1xuLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjk5NzE4OTgvaG93LXRvLWNyZWF0ZS1hbi1hY2N1cmF0ZS10aW1lci1pbi1qYXZhc2NyaXB0XG5cbmltcG9ydCBDb25maWcgZnJvbSAnLi4vLi4vaGVscGVycy9jb25maWcnO1xuaW1wb3J0IHsgTW9ua2V5VHlwZXMgfSBmcm9tICcuLi8uLi90eXBlcy90eXBlcyc7XG5pbXBvcnQgKiBhcyBNaXNjIGZyb20gJy4uLy4uL3V0aWxzL21pc2MnO1xuaW1wb3J0ICogYXMgVGltZXJFdmVudCBmcm9tICcuLi9vYnNlcnZhYmxlcy90aW1lci1ldmVudCc7XG5pbXBvcnQgKiBhcyBTbG93VGltZXIgZnJvbSAnLi4vc3RhdGVzL3Nsb3ctdGltZXInO1xuaW1wb3J0ICogYXMgVGVzdEFjdGl2ZSBmcm9tICcuLi9zdGF0ZXMvdGVzdC1hY3RpdmUnO1xuaW1wb3J0ICogYXMgVGltZSBmcm9tICcuLi9zdGF0ZXMvdGltZSc7XG5pbXBvcnQgKiBhcyBDYXJldCBmcm9tICcuL2NhcmV0JztcbmltcG9ydCAqIGFzIEN1c3RvbVRleHQgZnJvbSAnLi9jdXN0b20tdGV4dCc7XG5pbXBvcnQgKiBhcyBUZXN0SW5wdXQgZnJvbSAnLi90ZXN0LWlucHV0JztcbmltcG9ydCAqIGFzIFRlc3RTdGF0cyBmcm9tICcuL3Rlc3Qtc3RhdHMnO1xuaW1wb3J0ICogYXMgVGVzdFdvcmRzIGZyb20gJy4vdGVzdC13b3Jkcyc7XG5pbXBvcnQgKiBhcyBUaW1lclByb2dyZXNzIGZyb20gJy4vdGltZXItcHJvZ3Jlc3MnO1xubGV0IHNsb3dUaW1lckNvdW50ID0gMDtcbmxldCB0aW1lcjogTm9kZUpTLlRpbWVvdXQgfCBudWxsID0gbnVsbDtcbmNvbnN0IGludGVydmFsID0gMTAwMDtcbmxldCBleHBlY3RlZCA9IDA7XG5cbmxldCB0aW1lckRlYnVnID0gZmFsc2U7XG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlVGltZXJEZWJ1ZygpOiB2b2lkIHtcbiAgdGltZXJEZWJ1ZyA9IHRydWU7XG59XG5cbmxldCBjaGVja0lmVGltZUlzVXBEaXNhYmxlZCA9IGZhbHNlO1xuZXhwb3J0IGZ1bmN0aW9uIGRpc2FibGVDaGVja0lmVGltZUlzVXAoKTogdm9pZCB7XG4gIGNoZWNrSWZUaW1lSXNVcERpc2FibGVkID0gdHJ1ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyKCk6IHZvaWQge1xuICBUaW1lLnNldCgwKTtcbiAgaWYgKHRpbWVyICE9PSBudWxsKSBjbGVhclRpbWVvdXQodGltZXIpO1xufVxuXG5mdW5jdGlvbiBwcmVtaWQoKTogdm9pZCB7XG4gIGlmICh0aW1lckRlYnVnKSBjb25zb2xlLnRpbWUoJ3ByZW1pZCcpO1xuICBjb25zdCBwcmVtaWRTZWNvbmRzTGVmdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcmVtaWRTZWNvbmRzTGVmdCcpO1xuXG4gIGlmIChwcmVtaWRTZWNvbmRzTGVmdCAhPT0gbnVsbCkge1xuICAgIHByZW1pZFNlY29uZHNMZWZ0LmlubmVySFRNTCA9IChDb25maWcudGltZSAtIFRpbWUuZ2V0KCkpLnRvU3RyaW5nKCk7XG4gIH1cbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZUVuZCgncHJlbWlkJyk7XG59XG5cbmZ1bmN0aW9uIHVwZGF0ZVRpbWVyKCk6IHZvaWQge1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lKCd0aW1lciBwcm9ncmVzcyB1cGRhdGUnKTtcbiAgaWYgKENvbmZpZy5tb2RlID09PSAndGltZScgfHwgKENvbmZpZy5tb2RlID09PSAnY3VzdG9tJyAmJiBDdXN0b21UZXh0LmlzVGltZVJhbmRvbSkpIHtcbiAgICBUaW1lclByb2dyZXNzLnVwZGF0ZSgpO1xuICB9XG4gIGlmICh0aW1lckRlYnVnKSBjb25zb2xlLnRpbWVFbmQoJ3RpbWVyIHByb2dyZXNzIHVwZGF0ZScpO1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVXcG1SYXcoKTogTW9ua2V5VHlwZXMuV29yZHNQZXJNaW51dGVBbmRSYXcge1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lKCdjYWxjdWxhdGUgd3BtIGFuZCByYXcnKTtcbiAgY29uc3Qgd3BtQW5kUmF3ID0gVGVzdFN0YXRzLmNhbGN1bGF0ZVdwbUFuZFJhdygpO1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lRW5kKCdjYWxjdWxhdGUgd3BtIGFuZCByYXcnKTtcbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZSgncHVzaCB0byBoaXN0b3J5Jyk7XG4gIFRlc3RJbnB1dC5wdXNoVG9XcG1IaXN0b3J5KHdwbUFuZFJhdy53cG0pO1xuICBUZXN0SW5wdXQucHVzaFRvUmF3SGlzdG9yeSh3cG1BbmRSYXcucmF3KTtcbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZUVuZCgncHVzaCB0byBoaXN0b3J5Jyk7XG4gIHJldHVybiB3cG1BbmRSYXc7XG59XG5cbmZ1bmN0aW9uIG1vbmtleSh3cG1BbmRSYXc6IE1vbmtleVR5cGVzLldvcmRzUGVyTWludXRlQW5kUmF3KTogdm9pZCB7XG4gIGlmICh0aW1lckRlYnVnKSBjb25zb2xlLnRpbWUoJ3VwZGF0ZSBtb25rZXknKTtcbiAgY29uc3QgbnVtID0gQ29uZmlnLmJsaW5kTW9kZSA/IHdwbUFuZFJhdy5yYXcgOiB3cG1BbmRSYXcud3BtO1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lRW5kKCd1cGRhdGUgbW9ua2V5Jyk7XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZUFjYygpOiBudW1iZXIge1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lKCdjYWxjdWxhdGUgYWNjJyk7XG4gIGNvbnN0IGFjYyA9IE1pc2Mucm91bmRUbzIoVGVzdFN0YXRzLmNhbGN1bGF0ZUFjY3VyYWN5KCkpO1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lRW5kKCdjYWxjdWxhdGUgYWNjJyk7XG4gIHJldHVybiBhY2M7XG59XG5cbmZ1bmN0aW9uIGxheW91dGZsdWlkKCk6IHZvaWQge1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lKCdsYXlvdXRmbHVpZCcpO1xuICBpZiAoQ29uZmlnLmZ1bmJveCA9PT0gJ2xheW91dGZsdWlkJyAmJiBDb25maWcubW9kZSA9PT0gJ3RpbWUnKSB7XG4gICAgY29uc3QgbGF5b3V0cyA9IENvbmZpZy5jdXN0b21MYXlvdXRmbHVpZFxuICAgICAgPyBDb25maWcuY3VzdG9tTGF5b3V0Zmx1aWQuc3BsaXQoJyMnKVxuICAgICAgOiBbJ3F3ZXJ0eScsICdkdm9yYWsnLCAnY29sZW1hayddO1xuICAgIGNvbnN0IHN3aXRjaFRpbWUgPSBDb25maWcudGltZSAvIGxheW91dHMubGVuZ3RoO1xuICAgIGNvbnN0IHRpbWUgPSBUaW1lLmdldCgpO1xuICAgIGNvbnN0IGluZGV4ID0gTWF0aC5mbG9vcih0aW1lIC8gc3dpdGNoVGltZSk7XG4gICAgY29uc3QgbGF5b3V0ID0gbGF5b3V0c1tpbmRleF07XG4gICAgY29uc3QgZmxvb3JlZFN3aXRjaFRpbWVzID0gW107XG5cbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IGxheW91dHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGZsb29yZWRTd2l0Y2hUaW1lcy5wdXNoKE1hdGguZmxvb3Ioc3dpdGNoVGltZSAqIGkpKTtcbiAgICB9XG4gIH1cbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZUVuZCgnbGF5b3V0Zmx1aWQnKTtcbn1cblxuZnVuY3Rpb24gY2hlY2tJZkZhaWxlZCh3cG1BbmRSYXc6IE1vbmtleVR5cGVzLldvcmRzUGVyTWludXRlQW5kUmF3LCBhY2M6IG51bWJlcik6IHZvaWQge1xuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lKCdmYWlsIGNvbmRpdGlvbnMnKTtcbiAgVGVzdElucHV0LnB1c2hLZXlwcmVzc2VzVG9IaXN0b3J5KCk7XG4gIGlmIChcbiAgICBDb25maWcubWluV3BtID09PSAnY3VzdG9tJyAmJlxuICAgIHdwbUFuZFJhdy53cG0gPCBDb25maWcubWluV3BtQ3VzdG9tU3BlZWQgJiZcbiAgICBUZXN0V29yZHMud29yZHMuY3VycmVudEluZGV4ID4gM1xuICApIHtcbiAgICBpZiAodGltZXIgIT09IG51bGwpIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgU2xvd1RpbWVyLmNsZWFyKCk7XG4gICAgc2xvd1RpbWVyQ291bnQgPSAwO1xuICAgIFRpbWVyRXZlbnQuZGlzcGF0Y2goJ2ZhaWwnLCAnbWluIHdwbScpO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoQ29uZmlnLm1pbkFjYyA9PT0gJ2N1c3RvbScgJiYgYWNjIDwgQ29uZmlnLm1pbkFjY0N1c3RvbSkge1xuICAgIGlmICh0aW1lciAhPT0gbnVsbCkgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICBTbG93VGltZXIuY2xlYXIoKTtcbiAgICBzbG93VGltZXJDb3VudCA9IDA7XG4gICAgVGltZXJFdmVudC5kaXNwYXRjaCgnZmFpbCcsICdtaW4gYWNjdXJhY3knKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZUVuZCgnZmFpbCBjb25kaXRpb25zJyk7XG59XG5cbmZ1bmN0aW9uIGNoZWNrSWZUaW1lSXNVcCgpOiB2b2lkIHtcbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZSgndGltZXMgdXAgY2hlY2snKTtcbiAgaWYgKENvbmZpZy5tb2RlID09ICd0aW1lJyB8fCAoQ29uZmlnLm1vZGUgPT09ICdjdXN0b20nICYmIEN1c3RvbVRleHQuaXNUaW1lUmFuZG9tKSkge1xuICAgIGlmIChcbiAgICAgIChUaW1lLmdldCgpID49IENvbmZpZy50aW1lICYmIENvbmZpZy50aW1lICE9PSAwICYmIENvbmZpZy5tb2RlID09PSAndGltZScpIHx8XG4gICAgICAoVGltZS5nZXQoKSA+PSBDdXN0b21UZXh0LnRpbWUgJiYgQ3VzdG9tVGV4dC50aW1lICE9PSAwICYmIENvbmZpZy5tb2RlID09PSAnY3VzdG9tJylcbiAgICApIHtcbiAgICAgIC8vdGltZXMgdXBcbiAgICAgIGlmICh0aW1lciAhPT0gbnVsbCkgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgIENhcmV0LmhpZGUoKTtcbiAgICAgIFRlc3RJbnB1dC5pbnB1dC5wdXNoSGlzdG9yeSgpO1xuICAgICAgVGVzdElucHV0LmNvcnJlY3RlZC5wdXNoSGlzdG9yeSgpO1xuICAgICAgU2xvd1RpbWVyLmNsZWFyKCk7XG4gICAgICBzbG93VGltZXJDb3VudCA9IDA7XG4gICAgICBUaW1lckV2ZW50LmRpc3BhdGNoKCdmaW5pc2gnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZUVuZCgndGltZXMgdXAgY2hlY2snKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmxldCB0aW1lclN0YXRzOiBNb25rZXlUeXBlcy5UaW1lclN0YXRzW10gPSBbXTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRpbWVyU3RhdHMoKTogTW9ua2V5VHlwZXMuVGltZXJTdGF0c1tdIHtcbiAgcmV0dXJuIHRpbWVyU3RhdHM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRpbWVyU3RlcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKHRpbWVyRGVidWcpIGNvbnNvbGUudGltZSgndGltZXIgc3RlcCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScpO1xuICBUaW1lLmluY3JlbWVudCgpO1xuICBwcmVtaWQoKTtcbiAgdXBkYXRlVGltZXIoKTtcbiAgY29uc3Qgd3BtQW5kUmF3ID0gY2FsY3VsYXRlV3BtUmF3KCk7XG4gIGNvbnN0IGFjYyA9IGNhbGN1bGF0ZUFjYygpO1xuICBtb25rZXkod3BtQW5kUmF3KTtcbiAgbGF5b3V0Zmx1aWQoKTtcbiAgY2hlY2tJZkZhaWxlZCh3cG1BbmRSYXcsIGFjYyk7XG4gIGlmICghY2hlY2tJZlRpbWVJc1VwRGlzYWJsZWQpIHtcbiAgICBjaGVja0lmVGltZUlzVXAoKTtcbiAgfVxuICBpZiAodGltZXJEZWJ1ZykgY29uc29sZS50aW1lRW5kKCd0aW1lciBzdGVwIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJyk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgU2xvd1RpbWVyLmNsZWFyKCk7XG4gIHNsb3dUaW1lckNvdW50ID0gMDtcbiAgdGltZXJTdGF0cyA9IFtdO1xuICBleHBlY3RlZCA9IFRlc3RTdGF0cy5zdGFydCArIGludGVydmFsO1xuICAoZnVuY3Rpb24gbG9vcCgpOiB2b2lkIHtcbiAgICBjb25zdCBkZWxheSA9IGV4cGVjdGVkIC0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgdGltZXJTdGF0cy5wdXNoKHtcbiAgICAgIGRhdGVOb3c6IERhdGUubm93KCksXG4gICAgICBub3c6IHBlcmZvcm1hbmNlLm5vdygpLFxuICAgICAgZXhwZWN0ZWQ6IGV4cGVjdGVkLFxuICAgICAgbmV4dERlbGF5OiBkZWxheSxcbiAgICB9KTtcbiAgICBpZiAoXG4gICAgICAoQ29uZmlnLm1vZGUgPT09ICd0aW1lJyAmJiBDb25maWcudGltZSA8IDEzMCAmJiBDb25maWcudGltZSA+IDApIHx8XG4gICAgICAoQ29uZmlnLm1vZGUgPT09ICd3b3JkcycgJiYgQ29uZmlnLndvcmRzIDwgMjUwICYmIENvbmZpZy53b3JkcyA+IDApXG4gICAgKSB7XG4gICAgICBpZiAoZGVsYXkgPCBpbnRlcnZhbCAvIDIpIHtcbiAgICAgICAgLy9zbG93IHRpbWVyXG4gICAgICAgIFNsb3dUaW1lci5zZXQoKTtcbiAgICAgIH1cbiAgICAgIGlmIChkZWxheSA8IGludGVydmFsIC8gMTApIHtcbiAgICAgICAgc2xvd1RpbWVyQ291bnQrKztcbiAgICAgICAgaWYgKHNsb3dUaW1lckNvdW50ID4gNSkge1xuICAgICAgICAgIFRpbWVyRXZlbnQuZGlzcGF0Y2goJ2ZhaWwnLCAnc2xvdyB0aW1lcicpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoIVRlc3RBY3RpdmUuZ2V0KCkpIHtcbiAgICAgICAgaWYgKHRpbWVyICE9PSBudWxsKSBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICBTbG93VGltZXIuY2xlYXIoKTtcbiAgICAgICAgc2xvd1RpbWVyQ291bnQgPSAwO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRpbWVyU3RlcCgpO1xuXG4gICAgICBleHBlY3RlZCArPSBpbnRlcnZhbDtcbiAgICAgIGxvb3AoKTtcbiAgICB9LCBkZWxheSk7XG4gIH0pKCk7XG59XG4iXX0=