@scratch/scratch-vm 11.0.0-beta.1

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 (175) hide show
  1. package/.jsdoc.json +20 -0
  2. package/.nvmrc +1 -0
  3. package/CHANGELOG.md +7004 -0
  4. package/LICENSE +12 -0
  5. package/README.md +120 -0
  6. package/TRADEMARK +1 -0
  7. package/commitlint.config.js +4 -0
  8. package/docs/extensions.md +527 -0
  9. package/package.json +103 -0
  10. package/release.config.js +13 -0
  11. package/src/blocks/scratch3_control.js +206 -0
  12. package/src/blocks/scratch3_core_example.js +69 -0
  13. package/src/blocks/scratch3_data.js +257 -0
  14. package/src/blocks/scratch3_event.js +137 -0
  15. package/src/blocks/scratch3_looks.js +612 -0
  16. package/src/blocks/scratch3_motion.js +288 -0
  17. package/src/blocks/scratch3_operators.js +154 -0
  18. package/src/blocks/scratch3_procedures.js +79 -0
  19. package/src/blocks/scratch3_sensing.js +336 -0
  20. package/src/blocks/scratch3_sound.js +350 -0
  21. package/src/dispatch/central-dispatch.js +143 -0
  22. package/src/dispatch/shared-dispatch.js +235 -0
  23. package/src/dispatch/worker-dispatch.js +110 -0
  24. package/src/engine/adapter.js +176 -0
  25. package/src/engine/block-utility.js +242 -0
  26. package/src/engine/blocks-execute-cache.js +19 -0
  27. package/src/engine/blocks-runtime-cache.js +78 -0
  28. package/src/engine/blocks.js +1299 -0
  29. package/src/engine/comment.js +56 -0
  30. package/src/engine/execute.js +580 -0
  31. package/src/engine/monitor-record.js +23 -0
  32. package/src/engine/mutation-adapter.js +48 -0
  33. package/src/engine/profiler.js +390 -0
  34. package/src/engine/runtime.js +2686 -0
  35. package/src/engine/scratch-blocks-constants.js +27 -0
  36. package/src/engine/sequencer.js +361 -0
  37. package/src/engine/stage-layering.js +29 -0
  38. package/src/engine/target.js +799 -0
  39. package/src/engine/thread.js +404 -0
  40. package/src/engine/variable.js +70 -0
  41. package/src/extension-support/argument-type.js +47 -0
  42. package/src/extension-support/block-type.js +50 -0
  43. package/src/extension-support/define-messages.js +18 -0
  44. package/src/extension-support/extension-manager.js +440 -0
  45. package/src/extension-support/extension-metadata.js +64 -0
  46. package/src/extension-support/extension-worker.js +59 -0
  47. package/src/extension-support/reporter-scope.js +18 -0
  48. package/src/extension-support/target-type.js +17 -0
  49. package/src/extensions/scratch3_boost/index.js +2113 -0
  50. package/src/extensions/scratch3_ev3/index.js +1355 -0
  51. package/src/extensions/scratch3_gdx_for/index.js +981 -0
  52. package/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +44 -0
  53. package/src/extensions/scratch3_makeymakey/index.js +396 -0
  54. package/src/extensions/scratch3_microbit/index.js +984 -0
  55. package/src/extensions/scratch3_music/assets/drums/1-snare.mp3 +0 -0
  56. package/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3 +0 -0
  57. package/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3 +0 -0
  58. package/src/extensions/scratch3_music/assets/drums/12-triangle.mp3 +0 -0
  59. package/src/extensions/scratch3_music/assets/drums/13-bongo.mp3 +0 -0
  60. package/src/extensions/scratch3_music/assets/drums/14-conga.mp3 +0 -0
  61. package/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3 +0 -0
  62. package/src/extensions/scratch3_music/assets/drums/16-guiro.mp3 +0 -0
  63. package/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3 +0 -0
  64. package/src/extensions/scratch3_music/assets/drums/18-cuica.mp3 +0 -0
  65. package/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3 +0 -0
  66. package/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3 +0 -0
  67. package/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3 +0 -0
  68. package/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3 +0 -0
  69. package/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3 +0 -0
  70. package/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3 +0 -0
  71. package/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3 +0 -0
  72. package/src/extensions/scratch3_music/assets/drums/9-claves.mp3 +0 -0
  73. package/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3 +0 -0
  74. package/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3 +0 -0
  75. package/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3 +0 -0
  76. package/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3 +0 -0
  77. package/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3 +0 -0
  78. package/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3 +0 -0
  79. package/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3 +0 -0
  80. package/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3 +0 -0
  81. package/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3 +0 -0
  82. package/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3 +0 -0
  83. package/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3 +0 -0
  84. package/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3 +0 -0
  85. package/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3 +0 -0
  86. package/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3 +0 -0
  87. package/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3 +0 -0
  88. package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3 +0 -0
  89. package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3 +0 -0
  90. package/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3 +0 -0
  91. package/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3 +0 -0
  92. package/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3 +0 -0
  93. package/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3 +0 -0
  94. package/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3 +0 -0
  95. package/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3 +0 -0
  96. package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3 +0 -0
  97. package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3 +0 -0
  98. package/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3 +0 -0
  99. package/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3 +0 -0
  100. package/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3 +0 -0
  101. package/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3 +0 -0
  102. package/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3 +0 -0
  103. package/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3 +0 -0
  104. package/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3 +0 -0
  105. package/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3 +0 -0
  106. package/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3 +0 -0
  107. package/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3 +0 -0
  108. package/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3 +0 -0
  109. package/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3 +0 -0
  110. package/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3 +0 -0
  111. package/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3 +0 -0
  112. package/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3 +0 -0
  113. package/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3 +0 -0
  114. package/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3 +0 -0
  115. package/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3 +0 -0
  116. package/src/extensions/scratch3_music/index.js +1333 -0
  117. package/src/extensions/scratch3_music/manifest.js +63 -0
  118. package/src/extensions/scratch3_pen/index.js +770 -0
  119. package/src/extensions/scratch3_speech2text/index.js +700 -0
  120. package/src/extensions/scratch3_text2speech/index.js +766 -0
  121. package/src/extensions/scratch3_translate/index.js +286 -0
  122. package/src/extensions/scratch3_video_sensing/debug.js +13 -0
  123. package/src/extensions/scratch3_video_sensing/index.js +594 -0
  124. package/src/extensions/scratch3_video_sensing/library.js +384 -0
  125. package/src/extensions/scratch3_video_sensing/math.js +76 -0
  126. package/src/extensions/scratch3_video_sensing/view.js +509 -0
  127. package/src/extensions/scratch3_wedo2/index.js +1616 -0
  128. package/src/import/load-costume.js +416 -0
  129. package/src/import/load-sound.js +116 -0
  130. package/src/index.js +10 -0
  131. package/src/io/ble.js +256 -0
  132. package/src/io/bt.js +202 -0
  133. package/src/io/clock.js +39 -0
  134. package/src/io/cloud.js +169 -0
  135. package/src/io/keyboard.js +146 -0
  136. package/src/io/mouse.js +145 -0
  137. package/src/io/mouseWheel.js +28 -0
  138. package/src/io/userData.js +24 -0
  139. package/src/io/video.js +210 -0
  140. package/src/playground/benchmark.css +83 -0
  141. package/src/playground/benchmark.js +753 -0
  142. package/src/playground/index.html +111 -0
  143. package/src/playground/suite.css +78 -0
  144. package/src/playground/suite.html +25 -0
  145. package/src/playground/suite.js +544 -0
  146. package/src/playground/video-sensing.html +18 -0
  147. package/src/playground/video-sensing.js +133 -0
  148. package/src/serialization/deserialize-assets.js +178 -0
  149. package/src/serialization/sb2.js +1295 -0
  150. package/src/serialization/sb2_specmap.js +1818 -0
  151. package/src/serialization/sb3.js +1320 -0
  152. package/src/serialization/serialize-assets.js +60 -0
  153. package/src/sprites/rendered-target.js +1115 -0
  154. package/src/sprites/sprite.js +177 -0
  155. package/src/util/base64-util.js +48 -0
  156. package/src/util/cast.js +218 -0
  157. package/src/util/clone.js +17 -0
  158. package/src/util/color.js +204 -0
  159. package/src/util/fetch-with-timeout.js +53 -0
  160. package/src/util/get-monitor-id.js +33 -0
  161. package/src/util/jsonrpc.js +114 -0
  162. package/src/util/log.js +4 -0
  163. package/src/util/math-util.js +122 -0
  164. package/src/util/maybe-format-message.js +18 -0
  165. package/src/util/new-block-ids.js +33 -0
  166. package/src/util/rateLimiter.js +73 -0
  167. package/src/util/scratch-link-websocket.js +133 -0
  168. package/src/util/string-util.js +94 -0
  169. package/src/util/task-queue.js +203 -0
  170. package/src/util/timer.js +103 -0
  171. package/src/util/uid.js +29 -0
  172. package/src/util/variable-util.js +48 -0
  173. package/src/util/xml-escape.js +33 -0
  174. package/src/virtual-machine.js +1586 -0
  175. package/webpack.config.js +134 -0
@@ -0,0 +1,48 @@
1
+ const html = require('htmlparser2');
2
+ const decodeHtml = require('decode-html');
3
+
4
+ /**
5
+ * Convert a part of a mutation DOM to a mutation VM object, recursively.
6
+ * @param {object} dom DOM object for mutation tag.
7
+ * @return {object} Object representing useful parts of this mutation.
8
+ */
9
+ const mutatorTagToObject = function (dom) {
10
+ const obj = Object.create(null);
11
+ obj.tagName = dom.name;
12
+ obj.children = [];
13
+ for (const prop in dom.attribs) {
14
+ if (prop === 'xmlns') continue;
15
+ obj[prop] = decodeHtml(dom.attribs[prop]);
16
+ // Note: the capitalization of block info in the following lines is important.
17
+ // The lowercase is read in from xml which normalizes case. The VM uses camel case everywhere else.
18
+ if (prop === 'blockinfo') {
19
+ obj.blockInfo = JSON.parse(obj.blockinfo);
20
+ delete obj.blockinfo;
21
+ }
22
+ }
23
+ for (let i = 0; i < dom.children.length; i++) {
24
+ obj.children.push(
25
+ mutatorTagToObject(dom.children[i])
26
+ );
27
+ }
28
+ return obj;
29
+ };
30
+
31
+ /**
32
+ * Adapter between mutator XML or DOM and block representation which can be
33
+ * used by the Scratch runtime.
34
+ * @param {(object|string)} mutation Mutation XML string or DOM.
35
+ * @return {object} Object representing the mutation.
36
+ */
37
+ const mutationAdpater = function (mutation) {
38
+ let mutationParsed;
39
+ // Check if the mutation is already parsed; if not, parse it.
40
+ if (typeof mutation === 'object') {
41
+ mutationParsed = mutation;
42
+ } else {
43
+ mutationParsed = html.parseDOM(mutation)[0];
44
+ }
45
+ return mutatorTagToObject(mutationParsed);
46
+ };
47
+
48
+ module.exports = mutationAdpater;
@@ -0,0 +1,390 @@
1
+ /**
2
+ * @fileoverview
3
+ * A way to profile Scratch internal performance. Like what blocks run during a
4
+ * step? How much time do they take? How much time is spent inbetween blocks?
5
+ *
6
+ * Profiler aims for to spend as little time inside its functions while
7
+ * recording. For this it has a simple internal record structure that records a
8
+ * series of values for each START and STOP event in a single array. This lets
9
+ * all the values be pushed in one call for the array. This simplicity allows
10
+ * the contents of the start() and stop() calls to be inlined in areas that are
11
+ * called frequently enough to want even greater performance from Profiler so
12
+ * what is recorded better reflects on the profiled code and not Profiler
13
+ * itself.
14
+ */
15
+
16
+ /**
17
+ * The next id returned for a new profile'd function.
18
+ * @type {number}
19
+ */
20
+ let nextId = 0;
21
+
22
+ /**
23
+ * The mapping of names to ids.
24
+ * @const {Object.<string, number>}
25
+ */
26
+ const profilerNames = {};
27
+
28
+ /**
29
+ * The START event identifier in Profiler records.
30
+ * @const {number}
31
+ */
32
+ const START = 0;
33
+
34
+ /**
35
+ * The STOP event identifier in Profiler records.
36
+ * @const {number}
37
+ */
38
+ const STOP = 1;
39
+
40
+ /**
41
+ * The number of cells used in the records array by a START event.
42
+ * @const {number}
43
+ */
44
+ const START_SIZE = 4;
45
+
46
+ /**
47
+ * The number of cells used in the records array by a STOP event.
48
+ * @const {number}
49
+ */
50
+ const STOP_SIZE = 2;
51
+
52
+ /**
53
+ * Stored reference to Performance instance provided by the Browser.
54
+ * @const {Performance}
55
+ */
56
+ const performance = typeof window === 'object' && window.performance;
57
+
58
+
59
+ /**
60
+ * Callback handle called by Profiler for each frame it decodes from its
61
+ * records.
62
+ * @callback FrameCallback
63
+ * @param {ProfilerFrame} frame
64
+ */
65
+
66
+ /**
67
+ * A set of information about a frame of execution that was recorded.
68
+ */
69
+ class ProfilerFrame {
70
+ /**
71
+ * @param {number} depth Depth of the frame in the recorded stack.
72
+ */
73
+ constructor (depth) {
74
+ /**
75
+ * The numeric id of a record symbol like Runtime._step or
76
+ * blockFunction.
77
+ * @type {number}
78
+ */
79
+ this.id = -1;
80
+
81
+ /**
82
+ * The amount of time spent inside the recorded frame and any deeper
83
+ * frames.
84
+ * @type {number}
85
+ */
86
+ this.totalTime = 0;
87
+
88
+ /**
89
+ * The amount of time spent only inside this record frame. Not
90
+ * including time in any deeper frames.
91
+ * @type {number}
92
+ */
93
+ this.selfTime = 0;
94
+
95
+ /**
96
+ * An arbitrary argument for the recorded frame. For example a block
97
+ * function might record its opcode as an argument.
98
+ * @type {*}
99
+ */
100
+ this.arg = null;
101
+
102
+ /**
103
+ * The depth of the recorded frame. This can help compare recursive
104
+ * funtions that are recorded. Each level of recursion with have a
105
+ * different depth value.
106
+ * @type {number}
107
+ */
108
+ this.depth = depth;
109
+
110
+ /**
111
+ * A summarized count of the number of calls to this frame.
112
+ * @type {number}
113
+ */
114
+ this.count = 0;
115
+ }
116
+ }
117
+
118
+ class Profiler {
119
+ /**
120
+ * @param {FrameCallback} onFrame a handle called for each recorded frame.
121
+ * The passed frame value may not be stored as it'll be updated with later
122
+ * frame information. Any information that is further stored by the handler
123
+ * should make copies or reduce the information.
124
+ */
125
+ constructor (onFrame = function () {}) {
126
+ /**
127
+ * A series of START and STOP values followed by arguments. After
128
+ * recording is complete the full set of records is reported back by
129
+ * stepping through the series to connect the relative START and STOP
130
+ * information.
131
+ * @type {Array.<*>}
132
+ */
133
+ this.records = [];
134
+
135
+ /**
136
+ * An array of frames incremented on demand instead as part of start
137
+ * and stop.
138
+ * @type {Array.<ProfilerFrame>}
139
+ */
140
+ this.increments = [];
141
+
142
+ /**
143
+ * An array of profiler frames separated by counter argument. Generally
144
+ * for Scratch these frames are separated by block function opcode.
145
+ * This tracks each time an opcode is called.
146
+ * @type {Array.<ProfilerFrame>}
147
+ */
148
+ this.counters = [];
149
+
150
+ /**
151
+ * A frame with no id or argument.
152
+ * @type {ProfilerFrame}
153
+ */
154
+ this.nullFrame = new ProfilerFrame(-1);
155
+
156
+ /**
157
+ * A cache of ProfilerFrames to reuse when reporting the recorded
158
+ * frames in records.
159
+ * @type {Array.<ProfilerFrame>}
160
+ */
161
+ this._stack = [new ProfilerFrame(0)];
162
+
163
+ /**
164
+ * A callback handle called with each decoded frame when reporting back
165
+ * all the recorded times.
166
+ * @type {FrameCallback}
167
+ */
168
+ this.onFrame = onFrame;
169
+
170
+ /**
171
+ * A reference to the START record id constant.
172
+ * @const {number}
173
+ */
174
+ this.START = START;
175
+
176
+ /**
177
+ * A reference to the STOP record id constant.
178
+ * @const {number}
179
+ */
180
+ this.STOP = STOP;
181
+ }
182
+
183
+ /**
184
+ * Start recording a frame of time for an id and optional argument.
185
+ * @param {number} id The id returned by idByName for a name symbol like
186
+ * Runtime._step.
187
+ * @param {?*} arg An arbitrary argument value to store with the frame.
188
+ */
189
+ start (id, arg) {
190
+ this.records.push(START, id, arg, performance.now());
191
+ }
192
+
193
+ /**
194
+ * Stop the current frame.
195
+ */
196
+ stop () {
197
+ this.records.push(STOP, performance.now());
198
+ }
199
+
200
+ /**
201
+ * Increment the number of times this symbol is called.
202
+ * @param {number} id The id returned by idByName for a name symbol.
203
+ */
204
+ increment (id) {
205
+ if (!this.increments[id]) {
206
+ this.increments[id] = new ProfilerFrame(-1);
207
+ this.increments[id].id = id;
208
+ }
209
+ this.increments[id].count += 1;
210
+ }
211
+
212
+ /**
213
+ * Find or create a ProfilerFrame-like object whose counter can be
214
+ * incremented outside of the Profiler.
215
+ * @param {number} id The id returned by idByName for a name symbol.
216
+ * @param {*} arg The argument for a frame that identifies it in addition
217
+ * to the id.
218
+ * @return {{count: number}} A ProfilerFrame-like whose count should be
219
+ * incremented for each call.
220
+ */
221
+ frame (id, arg) {
222
+ for (let i = 0; i < this.counters.length; i++) {
223
+ if (this.counters[i].id === id && this.counters[i].arg === arg) {
224
+ return this.counters[i];
225
+ }
226
+ }
227
+
228
+ const newCounter = new ProfilerFrame(-1);
229
+ newCounter.id = id;
230
+ newCounter.arg = arg;
231
+ this.counters.push(newCounter);
232
+ return newCounter;
233
+ }
234
+
235
+ /**
236
+ * Decode records and report all frames to `this.onFrame`.
237
+ */
238
+ reportFrames () {
239
+ const stack = this._stack;
240
+ let depth = 1;
241
+
242
+ // Step through the records and initialize Frame instances from the
243
+ // START and STOP events. START and STOP events are separated by events
244
+ // for deeper frames run by higher frames. Frames are stored on a stack
245
+ // and reinitialized for each START event. When a stop event is reach
246
+ // the Frame for the current depth has its final values stored and its
247
+ // passed to the current onFrame callback. This way Frames are "pushed"
248
+ // for each START event and "popped" for each STOP and handed to an
249
+ // outside handle to any desired reduction of the collected data.
250
+ for (let i = 0; i < this.records.length;) {
251
+ if (this.records[i] === START) {
252
+ if (depth >= stack.length) {
253
+ stack.push(new ProfilerFrame(depth));
254
+ }
255
+
256
+ // Store id, arg, totalTime, and initialize selfTime.
257
+ const frame = stack[depth++];
258
+ frame.id = this.records[i + 1];
259
+ frame.arg = this.records[i + 2];
260
+ // totalTime is first set as the time recorded by this START
261
+ // event. Once the STOP event is reached the stored start time
262
+ // is subtracted from the recorded stop time. The resulting
263
+ // difference is the actual totalTime, and replaces the start
264
+ // time in frame.totalTime.
265
+ //
266
+ // totalTime is used this way as a convenient member to store a
267
+ // value between the two events without needing additional
268
+ // members on the Frame or in a shadow map.
269
+ frame.totalTime = this.records[i + 3];
270
+ // selfTime is decremented until we reach the STOP event for
271
+ // this frame. totalTime will be added to it then to get the
272
+ // time difference.
273
+ frame.selfTime = 0;
274
+
275
+ i += START_SIZE;
276
+ } else if (this.records[i] === STOP) {
277
+ const now = this.records[i + 1];
278
+
279
+ const frame = stack[--depth];
280
+ // totalTime is the difference between the start event time
281
+ // stored in totalTime and the stop event time pulled from this
282
+ // record.
283
+ frame.totalTime = now - frame.totalTime;
284
+ // selfTime is the difference of this frame's totalTime and the
285
+ // sum of totalTime of deeper frames.
286
+ frame.selfTime += frame.totalTime;
287
+
288
+ // Remove this frames totalTime from the parent's selfTime.
289
+ stack[depth - 1].selfTime -= frame.totalTime;
290
+
291
+ // This frame occured once.
292
+ frame.count = 1;
293
+
294
+ this.onFrame(frame);
295
+
296
+ i += STOP_SIZE;
297
+ } else {
298
+ this.records.length = 0;
299
+ throw new Error('Unable to decode Profiler records.');
300
+ }
301
+ }
302
+
303
+ for (let j = 0; j < this.increments.length; j++) {
304
+ if (this.increments[j] && this.increments[j].count > 0) {
305
+ this.onFrame(this.increments[j]);
306
+ this.increments[j].count = 0;
307
+ }
308
+ }
309
+
310
+ for (let k = 0; k < this.counters.length; k++) {
311
+ if (this.counters[k].count > 0) {
312
+ this.onFrame(this.counters[k]);
313
+ this.counters[k].count = 0;
314
+ }
315
+ }
316
+
317
+ this.records.length = 0;
318
+ }
319
+
320
+ /**
321
+ * Lookup or create an id for a frame name.
322
+ * @param {string} name The name to return an id for.
323
+ * @return {number} The id for the passed name.
324
+ */
325
+ idByName (name) {
326
+ return Profiler.idByName(name);
327
+ }
328
+
329
+ /**
330
+ * Reverse lookup the name from a given frame id.
331
+ * @param {number} id The id to search for.
332
+ * @return {string} The name for the given id.
333
+ */
334
+ nameById (id) {
335
+ return Profiler.nameById(id);
336
+ }
337
+
338
+ /**
339
+ * Lookup or create an id for a frame name.
340
+ * @static
341
+ * @param {string} name The name to return an id for.
342
+ * @return {number} The id for the passed name.
343
+ */
344
+ static idByName (name) {
345
+ if (typeof profilerNames[name] !== 'number') {
346
+ profilerNames[name] = nextId++;
347
+ }
348
+ return profilerNames[name];
349
+ }
350
+
351
+ /**
352
+ * Reverse lookup the name from a given frame id.
353
+ * @static
354
+ * @param {number} id The id to search for.
355
+ * @return {string} The name for the given id.
356
+ */
357
+ static nameById (id) {
358
+ for (const name in profilerNames) {
359
+ if (profilerNames[name] === id) {
360
+ return name;
361
+ }
362
+ }
363
+ return null;
364
+ }
365
+
366
+ /**
367
+ * Profiler is only available on platforms with the Performance API.
368
+ * @return {boolean} Can the Profiler run in this browser?
369
+ */
370
+ static available () {
371
+ return (
372
+ typeof window === 'object' &&
373
+ typeof window.performance !== 'undefined');
374
+ }
375
+ }
376
+
377
+
378
+ /**
379
+ * A reference to the START record id constant.
380
+ * @const {number}
381
+ */
382
+ Profiler.START = START;
383
+
384
+ /**
385
+ * A reference to the STOP record id constant.
386
+ * @const {number}
387
+ */
388
+ Profiler.STOP = STOP;
389
+
390
+ module.exports = Profiler;