mumuki-laboratory 7.12.0 → 7.12.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6139ebdb5d0f4a7148fb6fd64c07a2b7c28ea534fdafe4593cb185ab2b95371
4
- data.tar.gz: cea3b7ec16acc73e48a58a9257194a22ad5cf6c46e4dc0530d2b2a92c93dc0cd
3
+ metadata.gz: e025a36f6aa947e6a39b8372e2a0f257d473143a9c5bef32575885fcf375312b
4
+ data.tar.gz: 81428a5522e48781ed29cde5b8f2c219f3388a8d36e1ae466f91ee412e69b246
5
5
  SHA512:
6
- metadata.gz: 95b409773eb897492565a17980ae66cb30e8fbb341edc2034b83d01f117b1f6d6ac1a47c7367179cbf67c430b3c02208c2bda9e5dbc347cd19e3de91ee4d3543
7
- data.tar.gz: d58e05c853128d3d12b188160066231494945cc571704b588899f4bf61a88b69054d7c50ffca51478328a39110cc346f24008dbccdd907c22a197515a60987b9
6
+ metadata.gz: 374aec02893b3e31880b6bb3bbaf1031e0c2b567ee1b25b8d03bb7a30bda810aa72f5ff9974d70cab6637cede23a8e734e95ec5e9a1357d14772300e64a0fc6f
7
+ data.tar.gz: 70637e35aa57f98661f78f787a15e181ed4737d4b1d3080adcf06e90f4564e5cec9b642055106cccf6ae29fbaa90b1695367c7ac424c89b225166f80ab007557
@@ -9,8 +9,10 @@ mumuki.load(() => {
9
9
  });
10
10
 
11
11
  function placeKidsAnimations() {
12
+ placeAnimation('.mu-kids-character-result-aborted', 'failure');
12
13
  placeAnimation('.mu-kids-character-animation', 'blink');
13
14
  placeAnimation('.mu-kids-character-context', 'context');
15
+ placeAnimation('.mu-kids-character-result', 'blink');
14
16
  }
15
17
 
16
18
  function placeAnimation(selector, clip) {
@@ -20,7 +22,7 @@ mumuki.load(() => {
20
22
 
21
23
  function atRandom(array) {
22
24
  return array[Math.floor(Math.random() * array.length)];
23
- }
25
+ }
24
26
 
25
27
  mumuki.characters = characters;
26
28
  });
@@ -1,379 +1,205 @@
1
- mumuki.load(() => {
2
- let $bubble = $('.mu-kids-character-speech-bubble').children('.mu-kids-character-speech-bubble-normal');
3
-
4
- let availableTabs = ['.description', '.hint'];
5
- let $speechParagraphs, paragraphHeight, scrollHeight, nextSpeechBlinking;
6
- let currentParagraphIndex = 0;
7
- let paragraphCount = 1;
8
- let paragraphsLines = 2;
9
- let $prevSpeech = $('.mu-kids-character-speech-bubble-normal > .mu-kids-prev-speech').hide();
10
- let $nextSpeech = $('.mu-kids-character-speech-bubble-normal > .mu-kids-next-speech');
11
- let $speechTabs = $('.mu-kids-character-speech-bubble-tabs > li:not(.separator)');
12
- let $defaultSpeechTabName = 'description';
13
- let $texts = $bubble.children(availableTabs.join(", "));
14
- let $hint = $('.mu-kids-hint');
15
- let $description = $('.mu-kids-description');
16
- let discussionsLinkHtml = $('#mu-kids-discussion-link-html').html();
17
- let $kidsContext = $('#mu-kids-context');
18
- let contextModalButton = new mumuki.Button($('.mu-kids-context .modal-footer button'));
19
-
20
- // It is important that context is shown as early as possible
21
- // in order to display the loading animation
22
- function showContext() {
23
- $kidsContext.modal({
1
+ mumuki.Kids = class {
2
+
3
+ constructor() {
4
+ this.initialize();
5
+ this.showContext();
6
+ $(document).ready(this.onReady.bind(this));
7
+ }
8
+
9
+ // ================
10
+ // == Public API ==
11
+ // ================
12
+
13
+ initialize() {
14
+ this.submitButton = new mumuki.submission.SubmitButton($('#kids-btn-retry'), $('.submission_control'));
15
+ this.resultActions = {};
16
+ this.$states = $('.mu-kids-states');
17
+ this.$state = $('.mu-kids-state');
18
+ this.$blocks = $('.mu-kids-blocks');
19
+ this.$exercise = $('.mu-kids-exercise');
20
+ this.$exerciseDescription = $('.mu-kids-exercise-description');
21
+ this.$stateImage = $('.mu-kids-state-image');
22
+ this.$contextModal = $('#mu-kids-context');
23
+ this.$resultsModal = $('#kids-results');
24
+ this.$resultsAbortedModal = $('#kids-results-aborted');
25
+ this.$bubbleCharacterAnimation = $('.mu-kids-character-animation');
26
+ this.$submissionResult = $('.submission-results');
27
+ }
28
+
29
+ showContext() {
30
+ this.$contextModal.modal({
24
31
  backdrop: 'static',
25
32
  keyboard: false
26
33
  });
27
34
  }
28
35
 
29
- $kidsContext.on('hidden.bs.modal', function () {
30
- animateSpeech();
31
- });
32
-
33
- showContext();
34
-
35
- function floatFromPx(value) {
36
- return parseFloat(value.substring(0, value.length - 2));
36
+ showNonAbortedPopup(data, animation_name, open_modal_delay_ms = 0) {
37
+ this.$submissionResult.html(data.html);
38
+ mumuki.presenterCharacter.playAnimation(animation_name, $('.mu-kids-character-result'));
39
+ setTimeout(() => this._openSubmissionResultModal(data), open_modal_delay_ms);
40
+ this.onNonAbortedPopupCall(data);
37
41
  }
38
42
 
39
- function resizeSpeechParagraphs(paragraphIndex) {
40
- var previousParagraphCount = paragraphCount;
41
- scrollHeight = $bubble[0].scrollHeight;
42
- paragraphHeight = floatFromPx($speechParagraphs.css('line-height')) * paragraphsLines;
43
- paragraphCount = Math.ceil(scrollHeight / paragraphHeight);
44
- var newParagraphIndex = Math.floor((paragraphCount / previousParagraphCount) * currentParagraphIndex);
45
- showParagraph(paragraphIndex || newParagraphIndex);
43
+ showAbortedPopup(_data) {
44
+ this.submitButton.disable();
45
+ this.$resultsAbortedModal.modal();
46
46
  }
47
47
 
48
- function tabParagraphs(selector) {
49
- return $('.mu-kids-character-speech-bubble > .mu-kids-character-speech-bubble-normal > div' + selector + ' > p');
50
- }
48
+ // ==================
49
+ // == Hook Methods ==
50
+ // ==================
51
51
 
52
- function updateSpeechParagraphs() {
53
- $speechParagraphs = tabParagraphs('.' + getSelectedTabName());
54
- resizeSpeechParagraphs(0);
52
+ _showSuccessPopup() {
53
+ this._mustImplementThisMethod()
55
54
  }
56
55
 
57
- function getSelectedTabName() {
58
- return $speechTabs.filter(".active").data('target') || $defaultSpeechTabName;
56
+ _showFailurePopup() {
57
+ this._mustImplementThisMethod()
59
58
  }
60
59
 
61
- function showParagraph(index) {
62
- $bubble[0].scrollTop = index * paragraphHeight;
63
- currentParagraphIndex = index;
64
- checkArrowsSpeechVisibility();
65
- }
60
+ // ====================
61
+ // == Event Callback ==
62
+ // ====================
66
63
 
67
- function checkArrowsSpeechVisibility() {
68
- setVisibility($prevSpeech, currentParagraphIndex !== 0);
69
- setVisibility($nextSpeech, currentParagraphIndex !== paragraphCount - 1);
64
+ onReady() {
65
+ // SubClasses may override this method
70
66
  }
71
67
 
72
- function setVisibility(element, isVisible) {
73
- isVisible ? element.show() : element.hide();
68
+ onResize() {
69
+ // SubClasses may override this method
74
70
  }
75
71
 
76
- /**
77
- * Assigns propert widths to the states and blocks areas
78
- * depending on the presence and type of available states
79
- *
80
- * @param {*} $muKidsStateImage
81
- * @param {*} $muKidsStatesContainer
82
- * @param {*} $muKidsBlocks
83
- * @param {number} fullMargin
84
- */
85
- function distributeAreas($muKidsStateImage, $muKidsStatesContainer, $muKidsBlocks, fullMargin) {
86
- if ($muKidsStateImage.children().length) {
87
- var ratio = $muKidsStatesContainer.hasClass('mu-kids-single-state') ? 1 : 2;
88
- $muKidsStatesContainer.width($muKidsStatesContainer.height() / ratio * 1.25 - fullMargin);
89
- } else {
90
- $muKidsStatesContainer.width(0);
91
- $muKidsBlocks.width('100%');
92
- }
72
+ onNonAbortedPopupCall(_data) {
73
+ // SubClasses may override this method
93
74
  }
94
75
 
95
- mumuki.kids = {
96
-
97
- // ==========
98
- // Public API
99
- // ==========
100
-
101
- // Sets a function that will be called each
102
- // time the states need to be resized. The function takes:
103
- //
104
- // * $state: a single state area
105
- // * fullMargin
106
- // * preferredWidth
107
- // * preferredHeight
108
- //
109
- // Runners must call this method on within the runner's editor.js extension
110
- registerStateScaler: function (scaler) {
111
- this._stateScaler = scaler;
112
- },
113
-
114
- // Sets a function that will be called each
115
- // time the blocks area needs to be resized. The function takes:
116
- //
117
- // * $blocks: the blocks area
118
- //
119
- // Runners must call this method on within the runner's editor.js extension
120
- registerBlocksAreaScaler: function (scaler) {
121
- this._blocksAreaScaler = scaler;
122
- },
123
-
124
- // Scales a single state.
125
- //
126
- // This method is called by the kids code, but the runner's editor.js extension may need
127
- // to perform additional calls to it.
128
- scaleState: function ($state, fullMargin) {
129
- const preferredWidth = $state.width() - fullMargin * 2;
130
- const preferredHeight = $state.height() - fullMargin * 2;
131
- this._stateScaler($state, fullMargin, preferredWidth, preferredHeight);
132
- },
133
-
134
- // Scales the blocks area.
135
- //
136
- // This method is called by the kids code, but the runner's editor.js extension may need
137
- // to perform additional calls to it.
138
- scaleBlocksArea: function ($blocks) {
139
- this._blocksAreaScaler($blocks);
140
- },
141
-
142
- // Displays the kids results, updating the progress bar
143
- // firing the modal and running appropriate animations.
144
- //
145
- // This method needs to be called by the runner's editor.html extension
146
- // in order to finish an exercise
147
- showResult: function (data) {
148
- mumuki.updateProgressBarAndShowModal(data);
149
- if (data.guide_finished_by_solution) return;
150
- mumuki.kids.resultAction[data.status](data);
151
- },
152
-
153
- // Restarts the kids exercise.
154
- //
155
- // This method may need to be called by the runner's editor.html extension
156
- // in order to recover from a failed submission
157
- restart: function () {
158
- mumuki.kids._hideMessageOnCharacterBubble();
159
- var $bubble = mumuki.kids._getCharacterBubble();
160
- Object.keys(mumuki.kids.resultAction).forEach($bubble.removeClass.bind($bubble));
161
- mumuki.presenterCharacter.playAnimation('talk', mumuki.kids._getCharacterImage());
162
- },
163
-
164
- disableContextModalButton: function () {
165
- contextModalButton.setWaiting();
166
- },
167
-
168
- enableContextModalButton: function () {
169
- contextModalButton.enable();
170
- },
171
-
172
- showContext,
173
-
174
- // ===========
175
- // Private API
176
- // ===========
177
-
178
- _updateSubmissionResult: function (html) {
179
- return $('.submission-results').html(html);
180
- },
181
-
182
- _getResultsModal: function () {
183
- return $('#kids-results');
184
- },
185
-
186
- _getResultsAbortedModal: function () {
187
- return $('#kids-results-aborted');
188
- },
189
-
190
- _getCharacterImage: function () {
191
- return $('.mu-kids-character > img');
192
- },
193
-
194
- _getCharacterBubble: function () {
195
- return $('.mu-kids-character-speech-bubble');
196
- },
197
-
198
- _getOverlay: function () {
199
- return $('.mu-kids-overlay');
200
- },
201
-
202
- _hideMessageOnCharacterBubble: function () {
203
- var $bubble = mumuki.kids._getCharacterBubble();
204
- $bubble.find('.mu-kids-character-speech-bubble-tabs').show();
205
- $bubble.find('.mu-kids-character-speech-bubble-normal').show();
206
- $bubble.find('.mu-kids-character-speech-bubble-failed').hide();
207
- $bubble.find('.mu-kids-discussion-link').remove();
208
- Object.keys(mumuki.kids.resultAction).forEach($bubble.removeClass.bind($bubble));
209
- mumuki.kids._getOverlay().hide()
210
- },
211
-
212
- _showMessageOnCharacterBubble: function (data) {
213
- const renderer = new mumuki.renderers.SpeechBubbleRenderer(mumuki.kids._getCharacterBubble());
214
- renderer.setDiscussionsLinkHtml(discussionsLinkHtml);
215
- renderer.setResponseData(data);
216
- renderer.render();
217
- mumuki.kids._getOverlay().show();
218
- },
219
-
220
- _showOnSuccessPopup: function (data) {
221
- mumuki.kids._updateSubmissionResult(data.html);
222
- mumuki.presenterCharacter.playAnimation('success_l', mumuki.kids._getCharacterImage());
223
- mumuki.kids._showMessageOnCharacterBubble(data);
224
- mumuki.presenterCharacter.playAnimation('success2_l', $('.mu-kids-character-success'));
225
- setTimeout(function () {
226
- var $resultsKidsModal = mumuki.kids._getResultsModal();
227
- if ($resultsKidsModal) {
228
- $resultsKidsModal.modal({
229
- backdrop: 'static',
230
- keyboard: false
231
- });
232
- $resultsKidsModal.find('.modal-header').first().html(data.title_html);
233
- $resultsKidsModal.find('.modal-footer').first().html(data.button_html);
234
- mumuki.kids._showCorollaryCharacter();
235
- $('.mu-close-modal').click(() => mumuki.kids._getResultsModal().modal('hide'));
236
- }
237
- }, 1000 * 4);
238
- },
239
-
240
- _showOnFailurePopup: function () {
241
- mumuki.kids.submitButton.disable();
242
- mumuki.kids._getResultsAbortedModal().modal();
243
- mumuki.submission.animateTimeoutError(mumuki.kids.submitButton);
244
- },
245
-
246
- _showOnCharacterBubble: function (data) {
247
- mumuki.presenterCharacter.playAnimation('failure', mumuki.kids._getCharacterImage());
248
- mumuki.kids._showMessageOnCharacterBubble(data);
249
- },
250
-
251
- _showCorollaryCharacter: function () {
252
- mumuki.characters.magnifying_glass.playAnimation('show', $('.mu-kids-corollary-animation'));
253
- },
254
-
255
- _stateScaler: function ($state, fullMargin, preferredWidth, preferredHeight) {
256
- var $table = $state.find('gs-board > table');
257
- if (!$table.length) return setTimeout(() => this.scaleState($state, fullMargin));
258
-
259
- console.warn("You are using the default states scaler, which is gobstones-specific. Please register your own scaler in the future");
260
-
261
- $table.css('transform', 'scale(1)');
262
- var scaleX = preferredWidth / $table.width();
263
- var scaleY = preferredHeight / $table.height();
264
- $table.css('transform', 'scale(' + Math.min(scaleX, scaleY) + ')');
265
- },
266
-
267
- _blocksAreaScaler: function ($blocks) {
268
- console.warn("You are using the default blocks scaler, which is blockly-specific. Please register your own scaler in the future");
269
-
270
- var $blockArea = $blocks.find('#blocklyDiv');
271
- var $blockSvg = $blocks.find('.blocklySvg');
272
-
273
- $blockArea.width($blocks.width());
274
- $blockArea.height($blocks.height());
275
-
276
- $blockSvg.width($blocks.width());
277
- $blockSvg.height($blocks.height());
278
- },
279
-
280
- resultAction: {}
281
-
282
- };
283
-
284
- mumuki.kids.submitButton = new mumuki.submission.SubmitButton($('#kids-btn-retry'), $('.submission_control'));
285
-
286
- function showPrevParagraph() {
287
- animateSpeech();
288
- showParagraph(currentParagraphIndex - 1);
76
+ onSubmissionResultModalOpen(_data) {
77
+ // SubClasses may override this method
289
78
  }
290
79
 
291
- function showNextParagraph() {
292
- animateSpeech();
293
- showParagraph(currentParagraphIndex + 1);
294
- clearInterval(nextSpeechBlinking);
80
+ // =================
81
+ // == Private API ==
82
+ // =================
83
+
84
+ _openSubmissionResultModal(data) {
85
+ this.$resultsModal.modal({ backdrop: 'static', keyboard: false })
86
+ this.$resultsModal.find('.modal-header').first().html(data.title_html)
87
+ this.$resultsModal.find('.modal-footer').first().html(data.button_html)
88
+ $('.mu-close-modal').click(() => this.$resultsModal.modal('hide'));
89
+ this.onSubmissionResultModalOpen(data);
295
90
  }
296
91
 
297
- function animateSpeech() {
298
- mumuki.presenterCharacter.playAnimation('talk', mumuki.kids._getCharacterImage());
92
+ // ==========================
93
+ // == Called by the runner ==
94
+ // ==========================
95
+
96
+ // Displays the exercise results, updating the progress bar
97
+ // firing the modal and running appropriate animations.
98
+ //
99
+ // This method needs to be called by the runner's editor.html extension
100
+ // in order to finish an exercise
101
+ showResult(data) {
102
+ mumuki.progress.updateProgressBarAndShowModal(data);
103
+ if (data.guide_finished_by_solution) return;
104
+ this.resultActions[data.status](data);
299
105
  }
300
106
 
301
- function animateHint() {
302
- mumuki.presenterCharacter.playAnimation('hint', mumuki.kids._getCharacterImage());
107
+ // Restarts the kids exercise.
108
+ //
109
+ // This method may need to be called by the runner's editor.html extension
110
+ // in order to recover from a failed submission
111
+ restart() {
112
+ this._mustImplementThisMethod();
303
113
  }
304
114
 
305
- mumuki.kids.resultAction.passed = mumuki.kids._showOnSuccessPopup;
306
- mumuki.kids.resultAction.passed_with_warnings = mumuki.kids._showOnCharacterBubble;
115
+ // =================================
116
+ // == Called by the assets loader ==
117
+ // =================================
307
118
 
308
- mumuki.kids.resultAction.aborted = mumuki.kids._showOnFailurePopup;
119
+ disableContextModalButton() {
120
+ this.$contextModalButton.setWaiting();
121
+ }
309
122
 
310
- mumuki.kids.resultAction.failed = mumuki.kids._showOnCharacterBubble;
311
- mumuki.kids.resultAction.errored = mumuki.kids._showOnCharacterBubble;
312
- mumuki.kids.resultAction.pending = mumuki.kids._showOnCharacterBubble;
123
+ enableContextModalButton() {
124
+ this.$contextModalButton.enable();
125
+ }
313
126
 
127
+ // ============
128
+ // == Helper ==
129
+ // ============
314
130
 
315
- $(document).ready(() => {
316
- // Speech initialization
317
- if (!$bubble.length) return;
131
+ _mustImplementThisMethod() {
132
+ throw new Error('TODO: implement method')
133
+ }
318
134
 
319
- availableTabs.forEach(function (tabSelector) {
320
- tabParagraphs(tabSelector).contents().unwrap().wrapAll('<p>');
321
- });
135
+ // ============
136
+ // == Scaler ==
137
+ // ============
138
+
139
+ // Sets a function that will be called each
140
+ // time the states need to be resized. The function takes:
141
+ //
142
+ // * $state: a single state area
143
+ // * fullMargin
144
+ // * preferredWidth
145
+ // * preferredHeight
146
+ //
147
+ // Runners must call this method on within the runner's editor.js extension
148
+ registerStateScaler(scaler) {
149
+ this._stateScaler = scaler;
150
+ }
322
151
 
323
- updateSpeechParagraphs();
324
-
325
- resizeSpeechParagraphs();
326
-
327
- $speechTabs.each(function (i) {
328
- var $tab = $($speechTabs[i]);
329
- if ($tab.data('target')) {
330
- $tab.click(function () {
331
- $speechTabs.removeClass('active');
332
- $tab.addClass('active');
333
- $texts.hide();
334
- $bubble.children('.' + $tab.data('target')).show();
335
- updateSpeechParagraphs();
336
- })
337
- }
338
- });
152
+ // Sets a function that will be called each
153
+ // time the blocks area needs to be resized. The function takes:
154
+ //
155
+ // * $blocks: the blocks area
156
+ //
157
+ // Runners must call this method on within the runner's editor.js extension
158
+ registerBlocksAreaScaler(scaler) {
159
+ this._blocksAreaScaler = scaler;
160
+ }
339
161
 
340
- if (paragraphCount > 1) {
341
- nextSpeechBlinking = mumuki.setInterval(() => $nextSpeech.fadeTo('slow', 0.1).fadeTo('slow', 1.0), 1000);
342
- }
162
+ // Scales a single state.
163
+ //
164
+ // This method is called by the kids code, but the runner's editor.js extension may need
165
+ // to perform additional calls to it.
166
+ scaleState($state, fullMargin) {
167
+ const preferredWidth = $state.width() - fullMargin * 2;
168
+ const preferredHeight = $state.height() - fullMargin * 2;
169
+ this._stateScaler($state, fullMargin, preferredWidth, preferredHeight);
170
+ }
343
171
 
344
- $nextSpeech.click(showNextParagraph);
345
- $prevSpeech.click(showPrevParagraph);
346
- $description.click(animateSpeech);
172
+ // Scales the blocks area.
173
+ //
174
+ // This method is called by the kids code, but the runner's editor.js extension may need
175
+ // to perform additional calls to it.
176
+ scaleBlocksArea($blocks) {
177
+ this._blocksAreaScaler($blocks);
178
+ }
347
179
 
348
- $hint.click(function () {
349
- animateHint();
350
- this.classList.remove('blink');
351
- });
180
+ _stateScaler($state, fullMargin, preferredWidth, preferredHeight) {
181
+ const $table = $state.find('gs-board > table');
182
+ if (!$table.length) return setTimeout(() => this.scaleState($state, fullMargin));
352
183
 
353
- // States initial resizing
354
- mumuki.resize(function () {
355
- var margin = 15;
356
- var fullMargin = margin * 2;
184
+ console.warn("You are using the default states scaler, which is gobstones-specific. Please register your own scaler in the future");
357
185
 
358
- let $muKidsStatesContainer = $('.mu-kids-states');
359
- let $muKidsStates = $('.mu-kids-state');
360
- let $muKidsBlocks = $('.mu-kids-blocks');
361
- let $muKidsExercise = $('.mu-kids-exercise');
362
- let $muKidsExerciseDescription = $('.mu-kids-exercise-description');
363
- let $muKidsStateImage = $('.mu-kids-state-image');
186
+ $table.css('transform', 'scale(1)');
187
+ const scaleX = preferredWidth / $table.width();
188
+ const scaleY = preferredHeight / $table.height();
189
+ $table.css('transform', 'scale(' + Math.min(scaleX, scaleY) + ')');
190
+ }
364
191
 
365
- distributeAreas($muKidsStateImage, $muKidsStatesContainer, $muKidsBlocks, fullMargin);
192
+ _blocksAreaScaler($blocks) {
193
+ console.warn("You are using the default blocks scaler, which is blockly-specific. Please register your own scaler in the future");
366
194
 
367
- if (!$muKidsExerciseDescription.hasClass('mu-kids-exercise-description-fixed')) {
368
- $muKidsExerciseDescription.width($muKidsExercise.width() - $muKidsStatesContainer.width() - margin);
369
- }
195
+ const $blockArea = $blocks.find('#blocklyDiv');
196
+ const $blockSvg = $blocks.find('.blocklySvg');
370
197
 
371
- $muKidsStates.each((index, state) => mumuki.kids.scaleState($(state), fullMargin));
372
- mumuki.kids.scaleBlocksArea($muKidsBlocks);
198
+ $blockArea.width($blocks.width());
199
+ $blockArea.height($blocks.height());
373
200
 
374
- if (paragraphCount <= 1) clearInterval(nextSpeechBlinking);
201
+ $blockSvg.width($blocks.width());
202
+ $blockSvg.height($blocks.height());
203
+ }
375
204
 
376
- resizeSpeechParagraphs();
377
- });
378
- })
379
- });
205
+ }