├── .gitignore ├── default.sb ├── icons.png ├── README.md ├── js ├── jscembed.js ├── scratchio.js ├── jdataview.js ├── blocks.js ├── datatypes.js └── jsscratch.js ├── LICENSE ├── index.html └── player.css /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.sb 3 | *.sb2 4 | *.ypr 5 | /bin -------------------------------------------------------------------------------- /default.sb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trumank/JsScratch/HEAD/default.sb -------------------------------------------------------------------------------- /icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trumank/JsScratch/HEAD/icons.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JsScratch 2 | 3 | JsScratch is a project player in JavaScript and HTML for MIT Scratch. -------------------------------------------------------------------------------- /js/jscembed.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var done = []; 3 | 4 | function update() { 5 | var divs = document.querySelectorAll('div[class=project]'); 6 | var i = divs.length; 7 | while (i--) { 8 | if (done.indexOf(divs[i]) === -1) { 9 | done.push(divs[i]); 10 | var project = jsc.createPlayer(divs[i].getAttribute('project'), divs[i].getAttribute('autoplay') === 'true'); 11 | window.player = project[1]; 12 | divs[i].innerHTML = ''; 13 | divs[i].appendChild(project[0]); 14 | } 15 | } 16 | } 17 | 18 | document.addEventListener('DOMContentLoaded', update, false); 19 | document.addEventListener("DOMNodeInserted", update, false); 20 | 21 | update(); 22 | }) (); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Truman Kilen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |canvas tag! Get Chrome!';
211 | subcon.appendChild(canvas);
212 |
213 | var progress = document.createElement('div');
214 | progress.setAttribute('class', 'progress');
215 | subcon.appendChild(progress);
216 |
217 | var bar = document.createElement('div');
218 | bar.setAttribute('class', 'bar');
219 | progress.appendChild(bar);
220 |
221 | var message = document.createElement('span');
222 | message.setAttribute('class', 'message');
223 | bar.appendChild(message);
224 |
225 | var flag = true;
226 |
227 | var player = new jsc.Player(url, canvas, autoplay, message, function (s) {
228 | bar.style.width = (parseFloat(getComputedStyle(progress).width) - 2) * s + 'px';
229 | }, function () {
230 | progress.addEventListener('webkitTransitionEnd', function () {
231 | if (flag) {
232 | subcon.removeChild(progress);
233 | flag = false;
234 | }
235 | }, false);
236 | progress.addEventListener('transitionend', function () {
237 | if (flag) {
238 | subcon.removeChild(progress);
239 | flag = false;
240 | }
241 | }, false);
242 | progress.className += ' fade';
243 |
244 | turbo.onclick = function () {
245 | player.setTurbo(turbo.checked);
246 | };
247 | start.onclick = function () {
248 | player.start();
249 | };
250 | stop.onclick = function () {
251 | player.stop();
252 | };
253 | });
254 |
255 | return [container, player];
256 | }
257 |
258 | Number.prototype.mod = function (n) {
259 | return ((this % n) + n) % n;
260 | };
261 |
262 |
263 | // Scriptable ////////////////////////////////////////
264 | jsc.Scriptable = function () {
265 | this.init();
266 | }
267 |
268 | jsc.Scriptable.prototype.init = function () {
269 | this.threads = [];
270 | this.filters = {};
271 | this.volume = 100;
272 | };
273 |
274 | jsc.Scriptable.prototype.initFields = function (fields, version) {
275 | jsc.initFieldsNamed.call(this, ['bounds', 'stage', 'children', 'color', 'flags'], fields);
276 | fields.nextField();
277 | jsc.initFieldsNamed.call(this, ['objName', 'variables', 'blocksBin', 'isClone', 'media', 'costume'], fields);
278 | };
279 |
280 | jsc.Scriptable.prototype.initBeforeLoad = function () {
281 | for (var i = 0; i < this.blocksBin.length; i++) {
282 | if (['EventHatMorph', 'KeyEventHatMorph', 'MouseClickEventHatMorph'].indexOf(this.blocksBin[i][1][0][0]) != -1) {
283 | this.threads.push(new jsc.Thread(this, this.blocksBin[i][1]));
284 | }
285 | }
286 |
287 | var key, list, val, num;
288 | if (this.lists) {
289 | for (key in this.lists) {
290 | list = this.lists[key][9];
291 | for (var i = 0; i < list.length; i++) {
292 | val = list[i];
293 | num = jsc.castNumberOrNull(val);
294 | list[i] = ((num !== null && num.toString() === val) ? num : val);
295 | }
296 | this.lists[key] = list;
297 | }
298 | } else {
299 | this.lists = {};
300 | }
301 |
302 | if (this.variables) {
303 | for (key in this.variables) {
304 | variable = this.variables[key];
305 |
306 | num = jsc.castNumberOrNull(variable);
307 | val = ((num === null) ? variable : num);
308 |
309 | this.variables[key] = {val:val};
310 | }
311 | } else {
312 | this.variables = {};
313 | }
314 |
315 | this.costumes = this.media.filter(function (e) {
316 | return e instanceof jsc.ImageMedia;
317 | });
318 | this.sounds = this.media.filter(function (e) {
319 | return e instanceof jsc.SoundMedia;
320 | });
321 |
322 | this.costumeIndex = this.costumes.indexOf(this.costume);
323 |
324 | if (!this.stage) {
325 | this.stage = this.getStage();
326 | }
327 | };
328 |
329 | jsc.Scriptable.prototype.setup = function () {
330 | this.allVariables = {};
331 |
332 | var key;
333 |
334 | for (key in this.variables) {
335 | this.allVariables[key] = this.variables[key];
336 | }
337 | for (key in this.stage.variables) {
338 | this.allVariables[key] = this.stage.variables[key];
339 | }
340 |
341 | for (key in this.stage.variables) {
342 | this.variables[key] = this.stage.variables[key];
343 | }
344 |
345 | for (key in this.stage.lists) {
346 | this.lists[key] = this.stage.lists[key];
347 | }
348 | };
349 |
350 | jsc.Scriptable.prototype.getStage = function () {
351 | if (this.parent instanceof jsc.Stage) {
352 | return this.parent;
353 | } else if (this instanceof jsc.Stage) {
354 | return this;
355 | }
356 | return null;
357 | };
358 |
359 | jsc.Scriptable.prototype.step = function () {
360 | this.stepThreads();
361 | };
362 |
363 | jsc.Scriptable.prototype.stepThreads = function () {
364 | for (var i = 0; i < this.threads.length; i++) {
365 | this.threads[i].step();
366 | }
367 | };
368 |
369 | jsc.Scriptable.prototype.isRunning = function () {
370 | for (var i = 0; i < this.threads.length; i++) {
371 | if (!this.threads[i].done) {
372 | return true;
373 | }
374 | }
375 | return false;
376 | };
377 |
378 | jsc.Scriptable.prototype.broadcast = function (broadcast) {
379 | for (var i = 0; i < this.threads.length; i++) {
380 | if (this.threads[i].hat[0] === 'EventHatMorph' && this.threads[i].hat[1].toLowerCase() === broadcast.toLowerCase() && this.threads[i].done) {
381 | this.threads[i].start();
382 | }
383 | }
384 | };
385 |
386 | jsc.Scriptable.prototype.stopAll = function () {
387 | for (var i = 0; i < this.threads.length; i++) {
388 | this.threads[i].stop();
389 | }
390 | };
391 |
392 | jsc.Scriptable.prototype.getCommandFunctionName = function (selector) {
393 | var special = {
394 | "xpos:":"setXPos",
395 | "ypos:":"setYPos",
396 | "heading:":"setHeading",
397 |
398 | "showBackground:":"lookLike",
399 | "nextBackground":"nextCostume",
400 |
401 | "broadcast:":"scratchBroadcast",
402 | "stopAll":"stopAllScripts"
403 | };
404 | if (special[selector]) {
405 | return special[selector];
406 | }
407 | var str = selector.replace(/\:/g, '');
408 | if (typeof this[str] === 'function') {
409 | return str;
410 | }
411 |
412 | console.log('Unknown command block \'' + selector + '\', ignoring...');
413 | return null;
414 | };
415 |
416 | jsc.Scriptable.prototype.getReporterFunctionName = function (selector) {
417 | var special = {
418 | "xpos":"getXPos",
419 | "ypos":"getYPos",
420 | "heading":"getHeading",
421 |
422 | "costumeIndex":"getCostumeIndex",
423 | "backgroundIndex":"getCostumeIndex",
424 |
425 | "timer":"getTimer",
426 |
427 | "=":"equals",
428 | ">":"greatorThan",
429 | "<":"lessThan",
430 |
431 | "|":"or",
432 | "&":"and",
433 |
434 | "readVariable":"getVariable"
435 | };
436 | if (special[selector]) {
437 | return special[selector];
438 | }
439 | var str = selector.replace(/\:/g, '');
440 | if (typeof this[str] === 'function') {
441 | return str;
442 | }
443 |
444 | console.log('Unknown reporter block \'' + selector + '\', ignoring...');
445 | return null;
446 | };
447 |
448 | jsc.Scriptable.prototype.isStage = function () {
449 | return false;
450 | };
451 |
452 | jsc.Scriptable.prototype.getAttribute = function (attribute) {
453 | switch (attribute) {
454 | case 'volume':
455 | return this.volume;
456 | }
457 | return 0;
458 | };
459 |
460 | jsc.Scriptable.prototype.getSound = function (sound) {
461 | var cast = jsc.castNumberOrNull(sound);
462 | if (cast === null) {
463 | for (var i = 0; i < this.sounds.length; i++) {
464 | if (this.sounds[i].name.toLowerCase() === sound.toString().toLowerCase()) {
465 | return this.sounds[i];
466 | }
467 | }
468 | } else {
469 | return this.sounds[(Math.round(cast) - 1).mod(this.sounds.length)];
470 | }
471 | return null;
472 | };
473 |
474 | jsc.Scriptable.prototype.getList = function (name) {
475 | return this.lists[name];
476 | };
477 |
478 | jsc.Scriptable.prototype.toListLine = function (arg, list) {
479 | if (typeof arg === 'string') {
480 | switch (arg.toString()) {
481 | case 'first':
482 | return 0;
483 | case 'last':
484 | return list.length - 1;
485 | case 'any':
486 | return Math.floor(Math.random() * list.length);
487 | default:
488 | i = jsc.castNumberOrNull(arg)
489 | if (i === null) {
490 | return -1;
491 | }
492 | i = Math.round(i);
493 | }
494 | } else if (typeof arg === 'number') {
495 | i = arg;
496 | } else {
497 | return -1;
498 | }
499 |
500 | if (i >= 1 && i <= list.length) {
501 | return i - 1;
502 | } else {
503 | return -1;
504 | }
505 | };
506 |
507 | jsc.Scriptable.prototype.coerceSprite = function (sprite) {
508 | if (sprite instanceof jsc.Scriptable) {
509 | return sprite;
510 | }
511 | return this.stage.getSprite(sprite.toString());
512 | };
513 |
514 | jsc.Scriptable.prototype.stopAllMySounds = function () {
515 | for (var i = 0; i < this.sounds.length; i++) {
516 | this.sounds[i].stop();
517 | }
518 | };
519 |
520 |
521 | // jsc.Stage /////////////////////////////////////////////
522 | jsc.Stage = function () {
523 | this.init();
524 | }
525 |
526 | jsc.Stage.prototype = new jsc.Scriptable();
527 | jsc.Stage.prototype.constructor = jsc.Stage;
528 | jsc.Stage.uber = jsc.Scriptable.prototype;
529 |
530 | jsc.Stage.prototype.init = function () {
531 | jsc.Stage.uber.init.call(this);
532 | this.turbo = false;
533 | this.broadcastQueue = [];
534 | this.timer = new jsc.Stopwatch();
535 | this.keys = [];
536 | this.mouse = new jsc.Point(0, 0);
537 | this.mouseDown = false;
538 | for (var i = 0; i < 255; i++) {
539 | this.keys.push(false);
540 | }
541 | };
542 |
543 | jsc.Stage.prototype.initFields = function (fields, version) {
544 | jsc.Stage.uber.initFields.call(this, fields, version);
545 | jsc.initFieldsNamed.call(this, ['zoom', 'hPan', 'vPan'], fields);
546 | if (version == 1) return;
547 | jsc.initFieldsNamed.call(this, ['obsoleteSavedState'], fields);
548 | if (version == 2) return;
549 | jsc.initFieldsNamed.call(this, ['sprites'], fields);
550 | if (version == 3) return;
551 | jsc.initFieldsNamed.call(this, ['volume', 'tempoBPM'], fields);
552 | if (version == 4) return;
553 | jsc.initFieldsNamed.call(this, ['sceneStates', 'lists'], fields);
554 | };
555 |
556 | jsc.Stage.prototype.initBeforeLoad = function () {
557 | jsc.Stage.uber.initBeforeLoad.call(this);
558 | };
559 |
560 | jsc.Stage.prototype.drawOn = function (ctx) {
561 | ctx.drawImage(this.costume.getImage(), 0, 0);
562 |
563 | this.penCtx.stroke();
564 | ctx.drawImage(this.penCanvas, 0, 0);
565 | this.penCtx.beginPath();
566 |
567 | for (var i = this.children.length - 1; i >= 0; i--) {
568 | this.children[i].drawOn && this.children[i].drawOn(ctx);
569 | }
570 | };
571 |
572 | jsc.Stage.prototype.drawAllButOn = function (ctx, sprite) {
573 | ctx.drawImage(this.costume.getImage(), 0, 0);
574 |
575 | this.penCtx.stroke();
576 | ctx.drawImage(this.penCanvas, 0, 0);
577 | this.penCtx.beginPath();
578 |
579 | for (var i = this.sprites.length - 1; i >= 0; i--) {
580 | if (this.sprites[i] !== sprite) {
581 | this.sprites[i].drawOn && this.sprites[i].drawOn(ctx);
582 | }
583 | }
584 | };
585 |
586 | jsc.Stage.prototype.setup = function () {
587 | this.ctx = this.canvas.getContext('2d');
588 | if (!this.penCanvas) {
589 | this.penCanvas = jsc.newCanvas(this.bounds.width(), this.bounds.height())
590 | }
591 | this.penCtx = this.penCanvas.getContext('2d');
592 | this.penCtx.lineCap = 'round';
593 |
594 | this.buffer1 = jsc.newCanvas(this.width(), this.height());
595 | this.bufferCtx1 = this.buffer1.getContext('2d');
596 |
597 | this.buffer2 = jsc.newCanvas(this.width(), this.height());
598 | this.bufferCtx2 = this.buffer2.getContext('2d');
599 |
600 | this.allVariables = this.variables;
601 |
602 | this.canvas.onclick = function () {
603 |
604 | };
605 |
606 | var self = this;
607 | this.canvas.addEventListener('keydown', function (e) {
608 | self.keydown(e);
609 | }, false);
610 | this.canvas.addEventListener('keyup', function (e) {
611 | self.keyup(e);
612 | }, false);
613 |
614 | this.canvas.addEventListener('mousemove', function (e) {
615 | self.mousemove(e);
616 | }, false);
617 | this.canvas.addEventListener('mouseup', function (e) {
618 | self.mouseup(e);
619 | }, false);
620 | this.canvas.addEventListener('mousedown', function (e) {
621 | self.mousedown(e);
622 | }, false);
623 |
624 | this.canvas.addEventListener('touchmove', function (e) {
625 | self.mousemove(e);
626 | }, false);
627 | this.canvas.addEventListener('touchend', function (e) {
628 | self.mouseup(e);
629 | }, false);
630 | this.canvas.addEventListener('touchstart', function (e) {
631 | self.mousedown(e);
632 | }, false);
633 |
634 | for (var i = 0; i < this.sprites.length; i++) {
635 | this.sprites[i].setup();
636 | }
637 |
638 | this.eventsByName = {};
639 |
640 | var threads = this.getAllThreads();
641 |
642 | for (var i = 0; i < threads.length; i++) {
643 | if (threads[i].hat[0] === 'EventHatMorph') {
644 | var name = threads[i].hat[1].toLowerCase();
645 | if (!this.eventsByName[name]) {
646 | this.eventsByName[name] = [];
647 | }
648 | this.eventsByName[name].push(threads[i]);
649 | }
650 | }
651 |
652 | setInterval(function () {
653 | self.step();
654 | }, 1000 / 30);
655 | };
656 |
657 | jsc.Stage.prototype.width = function () {
658 | return this.bounds.width();
659 | };
660 |
661 | jsc.Stage.prototype.height = function () {
662 | return this.bounds.height();
663 | };
664 |
665 | jsc.Stage.prototype.step = function () {
666 | var stopwatch;
667 | if (this.turbo) {
668 | stopwatch = new jsc.Stopwatch();
669 | }
670 |
671 | if (this.animationFrame) {
672 | this.addBroadcastToQueue('animationframe');
673 | this.animationFrame = false;
674 | }
675 |
676 | do {
677 | jsc.Stage.uber.step.call(this);
678 | for (var i = 0; i < this.sprites.length; i++) {
679 | this.sprites[i].step();
680 | }
681 | } while (this.turbo && stopwatch.getElapsed() < 30)
682 |
683 | this.ctx.clearRect(0, 0, this.bounds.width(), this.bounds.height())
684 | this.drawOn(this.ctx);
685 | };
686 |
687 | jsc.Stage.prototype.stepThreads = function () {
688 | for (var i = 0; i < this.broadcastQueue.length; i++) {
689 | if (this.broadcastQueue[i] === 'requestanimationframe') {
690 | this.animationFrame = true;
691 | }
692 | var events = this.eventsByName[this.broadcastQueue[i]];
693 | if (events) {
694 | for (var j = 0; j < events.length; j++) {
695 | if (events[j].done) {
696 | events[j].start();
697 | }
698 | }
699 | }
700 | }
701 | this.broadcastQueue = [];
702 | jsc.Stage.uber.stepThreads.call(this);
703 | };
704 |
705 | jsc.Stage.prototype.isRunning = function () {
706 | var running = jsc.Stage.uber.isRunning.call(this);
707 | for (var i = 0; i < this.sprites.length; i++) {
708 | running = running || this.sprites[i].isRunning();
709 | }
710 | return running;
711 | };
712 |
713 | jsc.Stage.prototype.isStage = function () {
714 | return true;
715 | };
716 |
717 | jsc.Stage.prototype.getAllThreads = function () {
718 | if (this.allThreads) {
719 | return this.allThreads;
720 | }
721 | var threads = this.threads;
722 | for (var i = 0; i < this.sprites.length; i++) {
723 | threads = threads.concat(this.sprites[i].threads);
724 | }
725 | return this.allThreads = threads;
726 | };
727 |
728 | jsc.Stage.prototype.addBroadcastToQueue = function (broadcast) {
729 | this.broadcastQueue.push(broadcast.toLowerCase());
730 | };
731 |
732 | jsc.Stage.prototype.stopAll = function () {
733 | jsc.Stage.uber.stopAll.call(this);
734 | for (var i = 0; i < this.sprites.length; i++) {
735 | this.sprites[i].stopAll();
736 | }
737 | this.stopAllSounds();
738 | };
739 |
740 | jsc.Stage.prototype.start = function () {
741 | this.stopAll();
742 | this.addBroadcastToQueue('Scratch-StartClicked');
743 | };
744 |
745 | jsc.Stage.prototype.origin = function () {
746 | return this.bounds.center();
747 | };
748 |
749 | jsc.Stage.prototype.toScratchCoords = function (point) {
750 | return point.subtract(this.bounds.center()).multiplyBy(new jsc.Point(1, -1));
751 | };
752 |
753 | jsc.Stage.prototype.fromScratchCoords = function (point) {
754 | return point.multiplyBy(new jsc.Point(1, -1)).add(this.bounds.center());
755 | };
756 |
757 | jsc.Stage.prototype.getSprite = function (name) {
758 | return this.sprites.filter(function (sprite) {
759 | return sprite.objName === name;
760 | })[0];
761 | };
762 |
763 | jsc.Stage.prototype.getAttribute = function (attribute) {
764 | switch (attribute) {
765 | case 'background #':
766 | return this.costumeIndex + 1;
767 | }
768 | return jsc.Stage.uber.getAttribute.call(attribute);
769 | };
770 |
771 | jsc.Stage.prototype.keydown = function (e) {
772 | e.preventDefault();
773 | this.keys[e.keyCode] = true;
774 | var threads = this.getAllThreads();
775 | var thread;
776 | for (var i = 0; i < threads.length; i++) {
777 | thread = threads[i];
778 | if (thread.done && thread.hat[0] === 'KeyEventHatMorph' && thread.hat[1] === e.keyCode) {
779 | thread.start();
780 | }
781 | }
782 | };
783 |
784 | jsc.Stage.prototype.keyup = function (e) {
785 | e.preventDefault();
786 | this.keys[e.keyCode] = false;
787 | };
788 |
789 | jsc.Stage.prototype.mousemove = function (e) {
790 | e.preventDefault();
791 | var bounds = this.canvas.getBoundingClientRect();
792 | this.mouse = new jsc.Point((e.offsetX || e.layerX) * this.canvas.width / bounds.width, (e.offsetY || e.layerY) * this.canvas.height / bounds.height);
793 | };
794 | jsc.Stage.prototype.mouseup = function (e) {
795 | e.preventDefault();
796 | this.mouseDown = false;
797 | };
798 | jsc.Stage.prototype.mousedown = function (e) {
799 | e.preventDefault();
800 | this.mouseDown = true;
801 |
802 | for (var i = 0; i < this.children.length; i++) {
803 | var sprite = this.children[i];
804 | if (sprite instanceof jsc.Sprite && sprite.isTouching('mouse') && sprite.filters.ghost < 100) {
805 | var threads = sprite.threads
806 | for (var j = 0; j < threads.length; j++) {
807 | if (threads[j].hat[0] === 'MouseClickEventHatMorph') {
808 | threads[j].start();
809 | }
810 | }
811 | break;
812 | }
813 | }
814 | };
815 |
816 | jsc.Stage.prototype.stopAllSounds = function () {
817 | jsc.Stage.uber.stopAllMySounds.call(this);
818 | for (var i = 0; i < this.sprites.length; i++) {
819 | this.sprites[i].stopAllMySounds();
820 | }
821 | };
822 |
823 |
824 | // Sprite ////////////////////////////////////////////
825 | jsc.Sprite = function () {
826 | this.init();
827 | }
828 |
829 | jsc.Sprite.prototype = new jsc.Scriptable();
830 | jsc.Sprite.prototype.constructor = jsc.Sprite;
831 | jsc.Sprite.uber = jsc.Scriptable.prototype;
832 |
833 |
834 | jsc.Sprite.prototype.init = function () {
835 | jsc.Sprite.uber.init.call(this);
836 | };
837 |
838 | jsc.Sprite.prototype.initFields = function (fields, version) {
839 | jsc.Sprite.uber.initFields.call(this, fields, version);
840 | jsc.initFieldsNamed.call(this, ['visibility', 'scalePoint', 'direction', 'rotationStyle'], fields);
841 | if (version == 1) return;
842 | jsc.initFieldsNamed.call(this, ['volume', 'tempoBPM', 'draggable'], fields);
843 | if (version == 2) return;
844 | jsc.initFieldsNamed.call(this, ['sceneStates', 'lists'], fields);
845 | };
846 |
847 | jsc.Sprite.prototype.initBeforeLoad = function () {
848 | jsc.Sprite.uber.initBeforeLoad.call(this);
849 | this.position = this.bounds.origin.add(this.costume.rotationCenter);
850 | this.hidden = (this.flags & 1) === 1;
851 | this.pen = {};
852 | this.pen.color = new jsc.Color(0, 0, 255);
853 | this.pen.hsl = this.pen.color.getHSL();
854 | this.pen.size = 1;
855 | this.boundingChanged = true;
856 | };
857 |
858 | jsc.Sprite.prototype.step = function () {
859 | this.stage.penCtx.moveTo(this.position.x - 0.5, this.position.y - 0.5);
860 | jsc.Sprite.uber.step.call(this);
861 | };
862 |
863 | jsc.Sprite.prototype.drawOn = function (ctx, debug) {
864 | if (this.hidden) {
865 | return;
866 | }
867 | var rc = this.costume.rotationCenter;
868 | var angle = this.direction.mod(360) * Math.PI / 180;
869 |
870 | ctx.save();
871 | ctx.translate(Math.round(this.position.x), Math.round(this.position.y));
872 | if (this.rotationStyle === 'normal') {
873 | ctx.rotate(angle);
874 | }
875 | ctx.scale(this.rotationStyle === 'leftRight' && (this.direction - 90).mod(360) < 180 ? -this.scalePoint.x : this.scalePoint.x, this.scalePoint.y);
876 | ctx.translate(-rc.x, -rc.y);
877 | var t = this.filters.ghost;
878 | if (typeof t !== 'undefined') {
879 | ctx.globalAlpha = Math.max(Math.min(1 - t / 100, 1), 0);
880 | }
881 |
882 | ctx.drawImage(this.costume.getImage(), 0, 0);
883 |
884 | ctx.globalAlpha = 1;
885 | if (debug) {
886 | ctx.lineWidth = 2;
887 | ctx.strokeStyle = '#FF0000';
888 | ctx.strokeRect(0, 0, this.costume.extent().x, this.costume.extent().y);
889 | }
890 |
891 | ctx.restore();
892 |
893 | if (debug) {
894 | ctx.strokeStyle = '#00FF00';
895 | var b = this.getBoundingBox();
896 | ctx.strokeRect(b.left(), b.top(), b.width(), b.height());
897 | }
898 | }
899 |
900 | jsc.Sprite.prototype.getBoundingBox = function () {
901 | if (!this.boundingChanged) {
902 | return this.boundingBox;
903 | }
904 | this.boundingChanged = false;
905 | var p = this.position;
906 | var rc = this.costume.rotationCenter;
907 |
908 | var xp1 = -rc.x;
909 | var yp1 = -rc.y;
910 |
911 | var xp2 = this.costume.extent().x - rc.x;
912 | var yp2 = this.costume.extent().y - rc.y;
913 |
914 | if (this.rotationStyle !== 'normal' || this.scratchHeading() === 90) {
915 | return this.boundingBox = new jsc.Rectangle(xp1, yp1, xp2, yp2).scaleBy(this.scalePoint.multiplyBy(new jsc.Point(this.rotationStyle === 'leftRight' && (this.direction - 90).mod(360) < 180 ? -1 : 1, 1))).translateBy(this.position).expandBy(1);
916 | }
917 |
918 | var rad = Math.PI/180 * (this.direction);
919 |
920 | var cos = Math.cos(rad);
921 | var sin = Math.sin(rad);
922 |
923 | var x1 = xp1 * cos - yp1 * sin;
924 | var y1 = xp1 * sin + yp1 * cos;
925 |
926 | var x2 = xp1 * cos - yp2 * sin;
927 | var y2 = xp1 * sin + yp2 * cos;
928 |
929 | var x3 = xp2 * cos - yp2 * sin;
930 | var y3 = xp2 * sin + yp2 * cos;
931 |
932 | var x4 = xp2 * cos - yp1 * sin;
933 | var y4 = xp2 * sin + yp1 * cos;
934 |
935 | var rx1 = Math.floor(p.x + Math.min(x1, x2, x3, x4) * this.scalePoint.x);
936 | var ry1 = Math.floor(p.y + Math.min(y1, y2, y3, y4) * this.scalePoint.y);
937 |
938 | var rx2 = Math.ceil(p.x + Math.max(x1, x2, x3, x4) * this.scalePoint.x);
939 | var ry2 = Math.ceil(p.y + Math.max(y1, y2, y3, y4) * this.scalePoint.y);
940 |
941 | return this.boundingBox = new jsc.Rectangle(rx1, ry1, rx2, ry2);
942 | };
943 |
944 | jsc.Sprite.prototype.isTouching = function (obj) {
945 | var stage = this.stage;
946 | if (obj === 'edge') {
947 | return !stage.bounds.containsRectangle(this.getBoundingBox().expandBy(-2).translateBy(1));
948 | }
949 | if (this.hidden) {
950 | return false;
951 | }
952 |
953 | var w = stage.width();
954 | var h = stage.height();
955 |
956 | var b1 = this.getBoundingBox();
957 |
958 | if (obj === 'mouse') {
959 | if (!b1.containsPoint(stage.mouse)) {
960 | return false;
961 | }
962 |
963 | var rc = this.costume.rotationCenter;
964 | var angle = this.direction.mod(360) * Math.PI / 180;
965 |
966 | var p = this.stage.mouse;
967 |
968 | p = p.translateBy(new jsc.Point(-Math.round(this.position.x), -Math.round(this.position.y)));
969 |
970 | p = p.scaleBy(new jsc.Point(1 / (this.rotationStyle === 'leftRight' && (this.direction - 90).mod(360) < 180 ? -this.scalePoint.x : this.scalePoint.x), 1 / this.scalePoint.y));
971 |
972 | if (this.rotationStyle === 'normal') {
973 | p = p.rotateBy(-angle);
974 | }
975 |
976 | p = p.translateBy(new jsc.Point(rc.x - 1, rc.y - 1));
977 |
978 | return this.costume.getImage().getContext('2d').getImageData(p.x, p.y, 1, 1).data[3] > 0;
979 | } else {
980 | var other = this.coerceSprite(obj);
981 | if (!other || other.hidden) {
982 | return false;
983 | }
984 |
985 | var b2 = other.getBoundingBox();
986 |
987 | if (!b1.intersects(b2)) {
988 | return false;
989 | }
990 |
991 | var bufferCtx1 = stage.bufferCtx1;
992 | bufferCtx1.clearRect(0, 0, w, h);
993 | var g = this.filters.ghost || 0;
994 | this.filters.ghost = 0;
995 | this.drawOn(bufferCtx1);
996 | this.filters.ghost = g;
997 |
998 | var bufferCtx2 = stage.bufferCtx2;
999 | bufferCtx2.clearRect(0, 0, w, h);
1000 | g = other.filters.ghost || 0;
1001 | other.filters.ghost = 0;
1002 | other.drawOn(bufferCtx2);
1003 | other.filters.ghost = g;
1004 |
1005 | var b = b1.intersect(b2);
1006 |
1007 | if (b.width() <= 0 || b.height() <= 0) {
1008 | return false;
1009 | }
1010 |
1011 | var t = bufferCtx1.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1012 | var s = bufferCtx2.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1013 | for (var i = 0; i < s.length; i += 4) {
1014 | if (t[i + 3] > 0 && s[i + 3] > 0) {
1015 | return true;
1016 | }
1017 | }
1018 | }
1019 | return false;
1020 | };
1021 |
1022 | jsc.Sprite.prototype.isTouchingColor = function (color) {
1023 | var stage = this.stage;
1024 | var w = stage.width();
1025 | var h = stage.height();
1026 |
1027 | var bufferCtx1 = stage.bufferCtx1;
1028 | bufferCtx1.clearRect(0, 0, w, h);
1029 | this.drawOn(bufferCtx1);
1030 |
1031 | var bufferCtx2 = stage.bufferCtx2;
1032 | bufferCtx2.clearRect(0, 0, w, h);
1033 | stage.drawAllButOn(bufferCtx2, this);
1034 |
1035 | var b = this.getBoundingBox();
1036 |
1037 | var t = bufferCtx1.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1038 | var s = bufferCtx2.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1039 |
1040 | var r = color.r;
1041 | var g = color.g;
1042 | var b = color.b;
1043 |
1044 | for (var i = 0; i < s.length; i += 4) {
1045 | if (t[i + 3] > 0 && s[i] === r && s[i + 1] === g && s[i + 2] === b) {
1046 | return true;
1047 | }
1048 | }
1049 | return false;
1050 | };
1051 |
1052 | jsc.Sprite.prototype.isColorTouchingColor = function (color1, color2) {
1053 | var stage = this.stage;
1054 | var w = stage.width();
1055 | var h = stage.height();
1056 |
1057 | var bufferCtx1 = stage.bufferCtx1;
1058 | bufferCtx1.clearRect(0, 0, w, h);
1059 | this.drawOn(bufferCtx1);
1060 |
1061 | var bufferCtx2 = stage.bufferCtx2;
1062 | bufferCtx2.clearRect(0, 0, w, h);
1063 | stage.drawAllButOn(bufferCtx2, this);
1064 |
1065 | var b = this.getBoundingBox();
1066 |
1067 | var t = bufferCtx1.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1068 | var s = bufferCtx2.getImageData(b.origin.x, b.origin.y, b.width(), b.height()).data;
1069 |
1070 | var r1 = color1.r;
1071 | var g1 = color1.g;
1072 | var b1 = color1.b;
1073 |
1074 | var r2 = color2.r;
1075 | var g2 = color2.g;
1076 | var b2 = color2.b;
1077 |
1078 | var cs = color1.toString();
1079 |
1080 | var cc = this.costume.colorCache[cs];
1081 |
1082 | if (!cc) {
1083 | cc = this.costume.colorCache[cs] = [];
1084 | var f = false;
1085 | for (var i = 0; i < s.length; i += 4) {
1086 | if (t[i] === r1 && t[i + 1] === g1 && t[i + 2] === b1 && t[i + 3] > 0) {
1087 | cc.push(i);
1088 | if (s[i] === r2 && s[i + 1] === g2 && s[i + 2] === b2 && s[i + 3] > 0) {
1089 | f = true;
1090 | }
1091 | }
1092 | }
1093 | return f;
1094 | }
1095 |
1096 | var i;
1097 | for (var j = 0; j < cc.length; j++) {
1098 | i = cc[j];
1099 | if (s[i] === r2 && s[i + 1] === g2 && s[i + 2] === b2 && s[i + 3] > 0) {
1100 | return true;
1101 | }
1102 | }
1103 | return false;
1104 | };
1105 |
1106 | jsc.Sprite.prototype.getRelativePosition = function () {
1107 | return this.position.subtract(this.stage.origin()).multiplyBy(new jsc.Point(1, -1));
1108 | };
1109 |
1110 | jsc.Sprite.prototype.setRelativePosition = function (point) {
1111 | this.setPosition(point.multiplyBy(new jsc.Point(1, -1)).add(this.stage.origin()));
1112 | };
1113 |
1114 | jsc.Sprite.prototype.setPosition = function (point) {
1115 | var ctx = this.stage.penCtx;
1116 | this.position = point;
1117 | if (this.penDown) {
1118 | ctx.lineTo(this.position.x - 0.5, this.position.y - 0.5);
1119 | } else {
1120 | ctx.moveTo(this.position.x - 0.5, this.position.y - 0.5);
1121 | }
1122 |
1123 | this.boundingChanged = this.hasMoved = true;
1124 | };
1125 |
1126 | jsc.Sprite.prototype.extent = function () {
1127 | return new jsc.Point(this.bounds.corner.x - this.bounds.origin.x, this.bounds.corner.y - this.bounds.origin.y);
1128 | };
1129 |
1130 | jsc.Sprite.prototype.getAttribute = function (attribute) {
1131 | var stage = this.stage;
1132 | switch (attribute) {
1133 | case 'x position':
1134 | return stage.toScratchCoords(this.position).x;
1135 | case 'y position':
1136 | return stage.toScratchCoords(this.position).y;
1137 | case 'direction':
1138 | return this.scratchHeading();
1139 | case 'costume #':
1140 | return this.costumeIndex + 1;
1141 | case 'size':
1142 | return Math.round(this.scalePoint.x * 100);
1143 | }
1144 | return jsc.Sprite.uber.getAttribute.call(attribute);
1145 | };
1146 |
1147 | jsc.Sprite.prototype.scratchHeading = function () {
1148 | return (this.direction + 90 + 179).mod(360) - 179;
1149 | };
1150 |
1151 | jsc.Sprite.prototype.updatePen = function () {
1152 | var penCtx = this.stage.penCtx;
1153 |
1154 | penCtx.stroke();
1155 |
1156 | penCtx.lineWidth = this.pen.size;
1157 | var hsl = this.pen.hsl;
1158 | penCtx.strokeStyle = 'hsl(' + (hsl[0] * 360) + ', ' + (hsl[1] * 100) + '%, ' + (hsl[2] * 100) + '%)';
1159 |
1160 | penCtx.beginPath();
1161 | penCtx.moveTo(this.position.x - 0.5, this.position.y - 0.5);
1162 | };
1163 |
1164 |
1165 | // Watcher ////////////////////////////////////////////
1166 | jsc.Watcher = function () {
1167 | this.init();
1168 | }
1169 |
1170 | jsc.Watcher.prototype.constructor = jsc.Watcher;
1171 |
1172 | jsc.Watcher.prototype.init = function () {
1173 | this.hidden = false;
1174 | };
1175 |
1176 | jsc.Watcher.prototype.initFields = function (fields) {
1177 | this.fields = fields;
1178 | };
1179 |
1180 | jsc.Watcher.prototype.initBeforeLoad = function () {
1181 | jsc.initFieldsNamed.call(this, ['bounds', 'parent'], this.fields);
1182 | this.mode = 0;
1183 | if (this.fields.fields[19]) {
1184 | this.mode = 1;
1185 | }
1186 | if (this.fields.fields[16] !== null) {
1187 | this.mode = 2;
1188 | }
1189 | this.sliderMin = this.fields.fields[20];
1190 | this.sliderMax = this.fields.fields[21];
1191 |
1192 | this.color = this.fields.fields[15][3];
1193 |
1194 | this.label = this.fields.fields[13][8];
1195 |
1196 | this.object = this.fields.fields[14][10];
1197 |
1198 | this.command = this.commandLookup[this.fields.fields[14][11]];
1199 | this.arg = this.fields.fields[14][13];
1200 |
1201 | this.value = 'watcher';
1202 | };
1203 |
1204 | jsc.Watcher.prototype.commandLookup = {
1205 | "getVar:":"getVariable",
1206 | "timer":"getTimer"
1207 | };
1208 |
1209 | jsc.Watcher.prototype.updateValue = function () {
1210 | this.value = this.object[this.command](this.arg);
1211 | if (typeof this.value === 'number') {
1212 | this.value = (Math.round(this.value * 1000) / 1000).toString();
1213 | }
1214 | };
1215 |
1216 | jsc.Watcher.prototype.drawOn = function (ctx) {
1217 | if (this.hidden) {
1218 | return;
1219 | }
1220 | this.updateValue();
1221 | ctx.font = 'bold 8pt Verdana';
1222 | var w = ctx.measureText(this.label).width + 30;
1223 |
1224 | ctx.font = '8pt Verdana';
1225 | w += Math.max(ctx.measureText(this.value).width, 30);
1226 |
1227 | this.bounds.corner.x = this.bounds.origin.x + w;
1228 |
1229 |
1230 | var x1 = this.bounds.origin.x + 0.5;
1231 | var y1 = this.bounds.origin.y + 0.5;
1232 | var x2 = this.bounds.corner.x + 0.5;
1233 | var y2 = this.bounds.corner.y + 0.5;
1234 |
1235 | var th = 21;
1236 |
1237 | var r = 7;
1238 |
1239 | this.drawRoundedRect(ctx, x1, y1, x2, y2, r);
1240 | ctx.fillStyle = 'rgba(193, 196, 199, 255)';
1241 | ctx.fill();
1242 | ctx.strokeStyle = 'rgba(148, 145, 145, 255)';
1243 | ctx.stroke();
1244 |
1245 | x1 += 5;
1246 |
1247 | ctx.fillStyle = 'black';
1248 | ctx.font = 'bold 8pt Verdana';
1249 | ctx.textBaseline = 'middle';
1250 | ctx.fillText(this.label, x1, y1 + th / 2);
1251 |
1252 | x1 += ctx.measureText(this.label).width + 5;
1253 |
1254 | r = 4;
1255 |
1256 | this.drawRoundedRect(ctx, x1, y1 + 2, x2 - 4, y1 + th - 2, r);
1257 | ctx.fillStyle = this.color.toString();
1258 | ctx.fill();
1259 | ctx.strokeStyle = 'white';
1260 | ctx.stroke();
1261 |
1262 | ctx.fillStyle = 'white';
1263 | ctx.font = '8pt Verdana';
1264 | w = ctx.measureText(this.value).width;
1265 | ctx.fillText(this.value, x1 + ((x2 - x1 - 4) / 2 - (w / 2)), y1 + th / 2);
1266 | };
1267 |
1268 | jsc.Watcher.prototype.drawRoundedRect = function (ctx, x1, y1, x2, y2, r) {
1269 | ctx.beginPath();
1270 | ctx.moveTo(x1 + r, y1);
1271 | ctx.arcTo(x2, y1, x2, y2, r);
1272 | ctx.lineTo(x2, y2 - r);
1273 | ctx.arcTo(x2, y2, x1, y2, r);
1274 | ctx.lineTo(x1 + r, y2);
1275 | ctx.arcTo(x1, y2, x1, y1, r);
1276 | ctx.lineTo(x1, y1 + r);
1277 | ctx.arcTo(x1, y1, x2, y1, r);
1278 | ctx.closePath();
1279 | };
1280 |
1281 |
1282 | // Thread /////////////////////////////////////////////////
1283 | jsc.Thread = function (object, script) {
1284 | this.init(object, script);
1285 | }
1286 |
1287 | jsc.Thread.prototype.init = function (object, script) {
1288 | this.object = object;
1289 | this.hat = script[0];
1290 | if (this.hat[0] === 'KeyEventHatMorph') {
1291 | var keys = {
1292 | "space": 32,
1293 | "up arrow": 38,
1294 | "down arrow": 40,
1295 | "right arrow": 39,
1296 | "left arrow": 37,
1297 | "up": 38,
1298 | "down": 40,
1299 | "right": 39,
1300 | "left": 37
1301 | };
1302 | this.hat[1] = keys[this.hat[1]] || this.hat[1].toUpperCase().charCodeAt(0);
1303 | }
1304 | this.colors = [];
1305 | this.wholeScript = this.script = this.compile(script.slice(1, script.length));
1306 | this.done = true;
1307 | };
1308 |
1309 | jsc.Thread.prototype.eval = function (script) {
1310 | var self = this.object;
1311 | var colors = this.colors;
1312 | var c = jsc.castNumber;
1313 | return eval(script);
1314 | };
1315 |
1316 | jsc.Thread.prototype.compile = function (script) {
1317 | if (script === null) {
1318 | return null;
1319 | }
1320 | var self = this.object;
1321 | var compiled = [];
1322 | var string = null;
1323 | var selector;
1324 | for (var i = 0; i < script.length; i++) {
1325 | selector = script[i][0];
1326 | if (this.specialBlocks.indexOf(selector) !== -1) {
1327 | if (string !== null) {
1328 | compiled.push(this.eval(string + '})'));
1329 | }
1330 | string = null;
1331 | compiled.push(this.compileSpecial(script[i]));
1332 | continue;
1333 | } else if (string === null) {
1334 | string = '(function(){';
1335 | }
1336 |
1337 | var special = this.compileSpecialCommand(script[i]);
1338 | if (special !== null) {
1339 | string += special;
1340 | } else {
1341 | var command = this.object.getCommandFunctionName(selector);
1342 |
1343 | if (command === null) {
1344 | continue;
1345 | }
1346 |
1347 | string += 'self.' + command + '(';
1348 | for (var j = 1; j < script[i].length; j++) {
1349 | string += this.compileArg(script[i][j]);
1350 | if (j !== script[i].length - 1) {
1351 | string += ',';
1352 | }
1353 | }
1354 | string += ');';
1355 | }
1356 | }
1357 | if (string !== null) {
1358 | compiled.push(this.eval(string + '})'));
1359 | }
1360 | return compiled;
1361 | };
1362 |
1363 | jsc.Thread.prototype.compileSpecialCommand = function (command) {
1364 | switch (command[0]) {
1365 | case 'changeVariable':
1366 | return 'self.changeVariable(' + this.compileArg(command[1]) + ',' + ((command[2] === 'changeVar:by:') ? 'true' : 'false') + ',' + this.compileArg(command[3], true) + ');';
1367 | case 'comment:':
1368 | return '';
1369 | case 'readVariable':
1370 | return 'self.allVariables[' + this.compileArg(command[1]) + '].val;';
1371 | }
1372 | return null;
1373 | };
1374 |
1375 | jsc.Thread.prototype.compileArg = function (arg, preferNumber) {
1376 | if (typeof arg === 'number') {
1377 | return arg;
1378 | }
1379 | if (typeof arg === 'string') {
1380 | /*if (preferNumber) {
1381 | var num = jsc.castNumberOrNull(arg);
1382 | if (num !== null) {
1383 | return arg;
1384 | }
1385 | }*/
1386 | return '\'' + this.escapeString(arg) + '\'';
1387 | }
1388 | if (arg instanceof jsc.Sprite) {
1389 | return '\'' + arg.objName + '\'';
1390 | }
1391 | if (arg instanceof jsc.Stage) {
1392 | return 'self.stage';
1393 | }
1394 | if (arg instanceof jsc.Color) {
1395 | //return 'new jsc.Color(' + arg.r + ',' + arg.g + ',' + arg.b + ',' + arg.a + ')';
1396 | this.colors.push(arg);
1397 | return 'colors[' + (this.colors.length - 1) + ']';
1398 | }
1399 | if (!(arg instanceof Array)) {
1400 | return arg;
1401 | }
1402 |
1403 | var special = this.compileSpecialArg(arg);
1404 | if (special !== null) {
1405 | return special;
1406 | }
1407 |
1408 | var reporter = this.object.getReporterFunctionName(arg[0]);
1409 |
1410 | if (reporter === null) {
1411 | return '0';
1412 | }
1413 |
1414 | var string = 'self.' + reporter + '(';
1415 | for (var i = 1; i < arg.length; i++) {
1416 | string += this.compileArg(arg[i]);
1417 | if (i !== arg.length - 1) {
1418 | string += ',';
1419 | }
1420 | }
1421 | return string + ')';
1422 | };
1423 |
1424 | jsc.Thread.prototype.compileSpecialArg = function (arg) {
1425 | switch (arg[0]) {
1426 | case '+':
1427 | return '(c(' + this.compileArg(arg[1]) + ') + c(' + this.compileArg(arg[2]) + '))';
1428 | case '-':
1429 | return '(c(' + this.compileArg(arg[1]) + ') - c(' + this.compileArg(arg[2]) + '))';
1430 | case '*':
1431 | return '(c(' + this.compileArg(arg[1]) + ') * c(' + this.compileArg(arg[2]) + '))';
1432 | case '/':
1433 | return '(c(' + this.compileArg(arg[1]) + ') / c(' + this.compileArg(arg[2]) + '))';
1434 |
1435 | case '\\\\':
1436 | return '(c(' + this.compileArg(arg[1]) + ').mod(c(' + this.compileArg(arg[2]) + ')))';
1437 |
1438 | case 'abs':
1439 | return 'Math.abs(' + this.compileArg(arg[1], true) + ')';
1440 |
1441 | case 'computeFunction:of:':
1442 | var f = arg[1];
1443 | var v = this.compileArg(arg[2], true);
1444 |
1445 | switch (f.toString().toLowerCase()) {
1446 | case 'abs':
1447 | return 'Math.abs(' + v + ')';
1448 | case 'sqrt':
1449 | return 'Math.sqrt(' + v + ')';
1450 | case 'sin':
1451 | return 'Math.sin(Math.PI/180*' + v + ')';
1452 | case 'cos':
1453 | return 'Math.cos(Math.PI/180*' + v + ')';
1454 | case 'tan':
1455 | return 'Math.tan(Math.PI/180*' + v + ')';
1456 | case 'asin':
1457 | return '180/Math.PI*Math.asin(Math.max(-1,Math.min(1,' + v + ')))';
1458 | case 'acos':
1459 | return '180/Math.PI*Math.acos(Math.max(-1,Math.min(1,' + v + ')))';
1460 | case 'atan':
1461 | return '180/Math.PI*Math.atan(' + v + ')';
1462 | case 'ln':
1463 | return 'Math.log(' + v + ')';
1464 | case 'log':
1465 | return 'Math.log(' + v + ')';
1466 | case 'e ^':
1467 | return 'Math.pow(Math.E,' + v + ')';
1468 | case '10 ^':
1469 | return 'Math.pow(10,' + v + ')';
1470 | }
1471 |
1472 | case 'answer':
1473 | return 'this.stage.answer';
1474 | }
1475 | return null;
1476 | };
1477 |
1478 | jsc.Thread.prototype.escapeString = function (string) {
1479 | return string.replace(/\\/g, '\\\\').
1480 | replace(/\u0008/g, '\\b').
1481 | replace(/\t/g, '\\t').
1482 | replace(/\n/g, '\\n').
1483 | replace(/\f/g, '\\f').
1484 | replace(/\r/g, '\\r').
1485 | replace(/'/g, '\\\'').
1486 | replace(/"/g, '\\"');
1487 | };
1488 |
1489 | jsc.Thread.prototype.compileReporter = function (predicate) {
1490 | var self = this.object;
1491 | return this.eval('(function(){return ' + this.compileArg(predicate) + '})');
1492 | };
1493 |
1494 | jsc.Thread.prototype.specialBlocks = ['doIf', 'doPlaySoundAndWait', 'doBroadcastAndWait', 'doIfElse', 'doRepeat', 'doUntil', 'doForever', 'doForeverIf', 'doReturn', 'doWaitUntil', 'wait:elapsed:from:', 'glideSecs:toX:y:elapsed:from:', 'doAsk'];
1495 |
1496 | jsc.Thread.prototype.compileSpecial = function (special) {
1497 | var compiled;
1498 | switch (special[0]) {
1499 | case 'wait:elapsed:from:':
1500 | compiled = [this.compileReporter(special[1])];
1501 | break;
1502 | case 'doForever':
1503 | compiled = [this.compile(special[1])];
1504 | break;
1505 | case 'doIf':
1506 | compiled = [this.compileReporter(special[1]), this.compile(special[2])];
1507 | break;
1508 | case 'doIfElse':
1509 | compiled = [this.compileReporter(special[1]), this.compile(special[2]), this.compile(special[3])];
1510 | break;
1511 | case 'doUntil':
1512 | compiled = [this.compileReporter(special[1]), this.compile(special[2])];
1513 | break;
1514 | case 'doRepeat':
1515 | compiled = [this.compileReporter(special[1]), this.compile(special[2])];
1516 | break;
1517 | case 'doWaitUntil':
1518 | compiled = [this.compileReporter(special[1])];
1519 | break;
1520 | case 'doBroadcastAndWait':
1521 | compiled = [this.compileReporter(special[1])];
1522 | break;
1523 | case 'doForeverIf':
1524 | compiled = [this.compileReporter(special[1]), this.compile(special[2])];
1525 | break;
1526 | case 'doReturn':
1527 | compiled = [];
1528 | break;
1529 | case 'doPlaySoundAndWait':
1530 | compiled = [this.compileReporter(special[1])];
1531 | break;
1532 | case 'glideSecs:toX:y:elapsed:from:':
1533 | compiled = [this.compileReporter(special[1]), this.compileReporter(special[2]), this.compileReporter(special[3])];
1534 | break;
1535 | case 'doAsk':
1536 |
1537 | }
1538 | return [this.specialBlocks.indexOf(special[0])].concat(compiled);
1539 | };
1540 |
1541 | jsc.Thread.prototype.start = function () {
1542 | this.index = 0;
1543 | this.stack = [];
1544 | this.done = this.yield = false;
1545 | this.timer = null;
1546 | this.temp = null;
1547 | this.script = this.wholeScript;
1548 | };
1549 |
1550 | jsc.Thread.prototype.stop = function () {
1551 | this.index = 0;
1552 | this.stack = [];
1553 | this.done = this.yield = true;
1554 | this.timer = null;
1555 | this.temp = null;
1556 | this.script = this.wholeScript;
1557 | };
1558 |
1559 | jsc.Thread.prototype.step = function () {
1560 | if (this.done) {
1561 | return;
1562 | }
1563 |
1564 | this.yield = false;
1565 |
1566 | while (!this.yield && !this.done) {
1567 | if (this.index >= this.script.length) {
1568 | if (this.stack.length == 0) {
1569 | this.done = true;
1570 | } else {
1571 | this.popState();
1572 | }
1573 | } else {
1574 | this.evalCommand(this.script[this.index]);
1575 | this.index++;
1576 | }
1577 | }
1578 | };
1579 |
1580 | jsc.Thread.prototype.evalCommand = function (block) {
1581 | if (typeof block === 'function') {
1582 | block();
1583 | return;
1584 | }
1585 |
1586 | this[block[0]](block);
1587 | };
1588 |
1589 | jsc.Thread.prototype[0] = function (block) {
1590 | if (block[1]()) {
1591 | this.evalCommandList(false, block[2]);
1592 | }
1593 | };
1594 |
1595 | jsc.Thread.prototype[1] = function (block) {
1596 | if (this.temp === null) {
1597 | this.temp = this.object.getSound(block[1]());
1598 | this.temp.play(this.object.volume);
1599 | this.evalCommandList(true);
1600 | return;
1601 | }
1602 | if (this.temp.playing) {
1603 | this.evalCommandList(true);
1604 | } else {
1605 | this.reset();
1606 | }
1607 | };
1608 |
1609 | jsc.Thread.prototype[2] = function (block) {
1610 | var self = this;
1611 | if (this.temp === null) {
1612 | this.temp = block[1]().toString().toLowerCase();
1613 | this.object.stage.addBroadcastToQueue(this.temp);
1614 | this.evalCommandList(true);
1615 | return;
1616 | }
1617 |
1618 | var threads = this.object.stage.eventsByName[this.temp];
1619 |
1620 | if (threads) {
1621 | for (var i = 0; i < threads.length; i++) {
1622 | if (!threads[i].done) {
1623 | this.evalCommandList(true);
1624 | return;
1625 | }
1626 | }
1627 | }
1628 |
1629 | this.reset();
1630 | };
1631 |
1632 | jsc.Thread.prototype[3] = function (block) {
1633 | this.evalCommandList(false, block[1]() ? block[2] : block[3]);
1634 | };
1635 |
1636 | jsc.Thread.prototype[4] = function (block) {
1637 | if (this.temp === null) {
1638 | this.temp = Math.round(jsc.castNumber(block[1]()));
1639 | }
1640 | if (this.temp <= 0) {
1641 | this.reset();
1642 | return;
1643 | }
1644 |
1645 | this.temp--;
1646 | this.evalCommandList(true, block[2]);
1647 | };
1648 |
1649 | jsc.Thread.prototype[5] = function (block) {
1650 | if (!block[1]()) {
1651 | this.evalCommandList(true, block[2]);
1652 | }
1653 | };
1654 |
1655 | jsc.Thread.prototype[6] = function (block) {
1656 | this.evalCommandList(true, block[1]);
1657 | };
1658 |
1659 | jsc.Thread.prototype[7] = function (block) {
1660 | this.evalCommandList(true, block[1]() ? block[2] : null);
1661 | };
1662 |
1663 | jsc.Thread.prototype[8] = function (block) {
1664 | this.stop();
1665 | };
1666 |
1667 | jsc.Thread.prototype[9] = function (block) {
1668 | if (!block[1]()) {
1669 | this.evalCommandList(true);
1670 | }
1671 | };
1672 |
1673 | jsc.Thread.prototype[10] = function (block) {
1674 | if (!this.timer) {
1675 | this.timer = new jsc.Stopwatch();
1676 | this.evalCommandList(true);
1677 | return;
1678 | } else if (this.timer.getElapsed() < jsc.castNumber(block[1]()) * 1000) {
1679 | this.evalCommandList(true);
1680 | return;
1681 | }
1682 | this.reset();
1683 | };
1684 |
1685 | jsc.Thread.prototype[11] = function (block) {
1686 | if (!this.temp) {
1687 | this.timer = new jsc.Stopwatch();
1688 | this.temp = [this.object.position, this.object.stage.fromScratchCoords(new jsc.Point(jsc.castNumber(block[2]()), jsc.castNumber(block[3]()))), jsc.castNumber(block[1]())];
1689 | } else if (this.timer.getElapsed() < this.temp[2] * 1000) {
1690 | this.object.position = this.temp[0].subtract(this.temp[1]).multiplyBy(this.timer.getElapsed() / -1000 / this.temp[2]).add(this.temp[0]);
1691 | } else {
1692 | this.object.position = this.temp[1];
1693 | this.reset();
1694 | return;
1695 | }
1696 | this.evalCommandList(true);
1697 | };
1698 |
1699 | jsc.Thread.prototype.evalCommandList = function (repeat, commands) {
1700 | if (repeat) {
1701 | this.yield = true;
1702 | } else {
1703 | this.index++;
1704 | this.timer = null;
1705 | this.temp = null;
1706 | }
1707 | this.pushState();
1708 | this.yield = false;
1709 | this.script = commands || [];
1710 | this.index = -1;
1711 | this.timer = null;
1712 | this.temp = null;
1713 | };
1714 |
1715 | jsc.Thread.prototype.reset = function () {
1716 | this.timer = null;
1717 | this.temp = null;
1718 | };
1719 |
1720 | jsc.Thread.prototype.pushState = function () {
1721 | this.stack.push({
1722 | yield: this.yield,
1723 | script: this.script,
1724 | index: this.index,
1725 | timer: this.timer,
1726 | temp: this.temp
1727 | });
1728 | };
1729 |
1730 | jsc.Thread.prototype.popState = function () {
1731 | if (this.stack.length == 0) {
1732 | this.script = [];
1733 | this.index = 0;
1734 | this.done = this.yield = true;
1735 | return;
1736 | }
1737 |
1738 | var oldState = this.stack.pop();
1739 | this.yield = oldState.yield;
1740 | this.script = oldState.script;
1741 | this.index = oldState.index;
1742 | this.timer = oldState.timer;
1743 | this.temp = oldState.temp;
1744 | };
1745 |
1746 |
1747 | // Stopwatch //////////////////////////////////////////////
1748 | jsc.Stopwatch = function () {
1749 | this.init();
1750 | }
1751 |
1752 | jsc.Stopwatch.prototype.init = function () {
1753 | this.startTime = Date.now();
1754 | };
1755 |
1756 | jsc.Stopwatch.prototype.reset = function () {
1757 | this.startTime = Date.now();
1758 | };
1759 |
1760 | jsc.Stopwatch.prototype.getElapsed = function () {
1761 | return Date.now() - this.startTime;
1762 | };
1763 |
1764 |
1765 | // ScratchMedia ///////////////////////////////////////////
1766 | jsc.ScratchMedia = function () {
1767 | this.name;
1768 | }
1769 |
1770 | jsc.ScratchMedia.prototype.initFields = function (fields, version) {
1771 | jsc.initFieldsNamed.call(this, ['name'], fields);
1772 | };
1773 |
1774 |
1775 | // ImageMedia /////////////////////////////////////////////
1776 | jsc.ImageMedia = function () {
1777 | this.colorCache = {};
1778 | }
1779 |
1780 | jsc.ImageMedia.prototype = new jsc.ScratchMedia();
1781 | jsc.ImageMedia.prototype.constructor = jsc.ImageMedia;
1782 | jsc.ImageMedia.uber = jsc.ScratchMedia.prototype;
1783 |
1784 | jsc.ImageMedia.prototype.initFields = function (fields, version) {
1785 | jsc.ImageMedia.uber.initFields.call(this, fields, version);
1786 | jsc.initFieldsNamed.call(this, ['form', 'rotationCenter'], fields);
1787 | if (version == 1) return;
1788 | jsc.initFieldsNamed.call(this, ['textBox'], fields);
1789 | if (version == 2) return;
1790 | jsc.initFieldsNamed.call(this, ['jpegBytes'], fields);
1791 | if (version == 3) return;
1792 | this.form = fields.nextField() || this.form;
1793 | };
1794 |
1795 | jsc.ImageMedia.prototype.initBeforeLoad = function () {
1796 | if(this.jpegBytes) {
1797 | var str = '';
1798 | for (var i = 0; i < this.jpegBytes.length; i++) {
1799 | str += String.fromCharCode(this.jpegBytes[i]);
1800 | }
1801 | this.base64 = 'data:image/jpeg;base64,' + btoa(str);
1802 | }
1803 | if (this.base64) {
1804 | this.image = jsc.newImage(this.base64);
1805 | } else {
1806 | this.image = null;
1807 | }
1808 | };
1809 |
1810 | jsc.ImageMedia.prototype.getImage = function () {
1811 | if (!this.image) {
1812 | this.image = this.form.getImage();
1813 | }
1814 | return this.image;
1815 | };
1816 |
1817 | jsc.ImageMedia.prototype.extent = function () {
1818 | return this.form.extent();
1819 | };
1820 |
1821 | jsc.ImageMedia.prototype.center = function () {
1822 | this.getImage();
1823 | return new jsc.Point(this.image.width / 2, this.image.height / 2);
1824 | };
1825 |
1826 |
1827 | // SoundMedia /////////////////////////////////////////////
1828 | jsc.SoundMedia = function () {
1829 |
1830 | }
1831 |
1832 | jsc.SoundMedia.prototype = new jsc.ScratchMedia();
1833 | jsc.SoundMedia.prototype.constructor = jsc.SoundMedia;
1834 | jsc.SoundMedia.uber = jsc.ScratchMedia.prototype;
1835 |
1836 | jsc.SoundMedia.prototype.initFields = function (fields, version) {
1837 | jsc.SoundMedia.uber.initFields.call(this, fields, version);
1838 | jsc.initFieldsNamed.call(this, ['originalSound', 'volume', 'balance'], fields);
1839 | if (version == 1) return;
1840 | jsc.initFieldsNamed.call(this, ['compressedSampleRate', 'compressedBitsPerSample', 'compressedData'], fields);
1841 | };
1842 |
1843 | jsc.SoundMedia.prototype.initBeforeLoad = function () {
1844 | var self = this;
1845 | this.audio = new Audio();
1846 | this.audio.addEventListener('ended', function () {
1847 | self.playing = false;
1848 | }, false);
1849 |
1850 | if (this.compressedData) {
1851 | this.decompress();
1852 | this.sampleRate = this.compressedSampleRate;
1853 | } else {
1854 | this.samples = this.originalSound.samples;
1855 | for (var i = 0; i < this.samples.length; i += 2) {
1856 | var swap = this.samples[i];
1857 | this.samples[i] = this.samples[i + 1];
1858 | this.samples[i + 1] = swap;
1859 | }
1860 | this.sampleRate = 22050;
1861 | }
1862 |
1863 | this.bitsPerSample = 16
1864 |
1865 | this.audio.src = jsc.createWave(this.samples, this.sampleRate, this.bitsPerSample);
1866 | this.playing = false;
1867 | };
1868 |
1869 | jsc.SoundMedia.prototype.stop = function () {
1870 | this.audio.pause();
1871 | try {
1872 | this.audio.currentTime = 0;
1873 | } catch (e) {}
1874 | this.playing = false;
1875 | };
1876 |
1877 | jsc.SoundMedia.prototype.play = function (volume) {
1878 | this.stop();
1879 | this.audio.volume = Math.max(Math.min(volume / 100, 1), 0);
1880 | this.audio.play();
1881 | this.playing = true;
1882 | };
1883 |
1884 | jsc.SoundMedia.prototype.setVolume = function (volume) {
1885 | this.audio.volume = volume;
1886 | };
1887 |
1888 | jsc.SoundMedia.prototype.decompress = function () {
1889 | var stepSizeTable = [7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767];
1890 |
1891 | var indices = [
1892 | [-1, 2],
1893 | [-1, -1, 2, 4],
1894 | [-1, -1, -1, -1, 2, 4, 6, 8],
1895 | [-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16]
1896 | ];
1897 |
1898 | var indexTable = indices[this.compressedBitsPerSample - 2];
1899 | var soundData = this.compressedData;
1900 | var bitsPerSample = this.compressedBitsPerSample;
1901 |
1902 | var l5 = 0;
1903 | var l6 = 0;
1904 | var l7 = 0;
1905 | var l8 = 0;
1906 | var l2 = [];
1907 | var l3 = 0;
1908 | var l4 = 0;
1909 |
1910 | var index = 0;
1911 |
1912 | var bitPosition = 0;
1913 | var currentByte = 0;
1914 |
1915 | var signMask = 1 << (bitsPerSample - 1);
1916 | var valueMask = signMask - 1;
1917 | var valueHighBit = signMask >> 1;
1918 |
1919 | while (true) {
1920 | l5 = nextCode.call(this);
1921 | if (l5 < 0) {
1922 | break;
1923 | }
1924 | l6 = stepSizeTable[l4];
1925 | l7 = 0;
1926 | l8 = valueHighBit;
1927 | while (l8 > 0) {
1928 | if ((l5 & l8) !== 0) {
1929 | l7 += l6;
1930 | }
1931 | l6 = l6 >> 1;
1932 | l8 = l8 >> 1;
1933 | }
1934 | l7 += l6;
1935 | l3 += ((l5 & signMask) === 0) ? l7 : -l7
1936 | l4 += indexTable[l5 & valueMask];
1937 | l4 = Math.min(Math.max(l4, 0), 88);
1938 | l3 = Math.min(Math.max(l3, -32768), 32767);
1939 | l2.push(l3 & 255);
1940 | l2.push((l3 >> 8) & 255);
1941 | }
1942 |
1943 | function nextCode() {
1944 | var j4 = 0;
1945 | var j2 = 0;
1946 | var j3 = bitsPerSample;
1947 |
1948 | while (true) {
1949 | j4 = j3 - bitPosition;
1950 | j2 += j4 < 0 ? currentByte >> -j4 : currentByte << j4;
1951 | if (j4 > 0) {
1952 | j3 -= bitPosition;
1953 | if (index < soundData.length) {
1954 | currentByte = soundData[index++];
1955 | bitPosition = 8;
1956 | } else {
1957 | currentByte = 0;
1958 | bitPosition = 0;
1959 | return -1;
1960 | }
1961 | } else {
1962 | bitPosition -= j3;
1963 | currentByte = currentByte & (255 >> (8 - bitPosition));
1964 | break;
1965 | }
1966 | }
1967 | return j2;
1968 | }
1969 | this.samples = l2;
1970 | };
1971 |
1972 | // SampledSound ///////////////////////////////////////////
1973 | jsc.SampledSound = function () {
1974 |
1975 | }
1976 |
1977 | jsc.SampledSound.prototype = new jsc.ScratchMedia();
1978 | jsc.SampledSound.prototype.constructor = jsc.SampledSound;
1979 |
1980 | jsc.SampledSound.prototype.initFields = function (fields, version) {
1981 | jsc.initFieldsNamed.call(this, ['envelopes', 'scaledVol', 'initialCount', 'samples', 'originalSamplingRate', 'samplesSize', 'scaledIncrement', 'scaledInitialIndex'], fields);
1982 | };
1983 |
1984 |
1985 | jsc.squeakColors = [new jsc.Color(255, 255, 255),
1986 | new jsc.Color(0, 0, 0),
1987 | new jsc.Color(255, 255, 255),
1988 | new jsc.Color(128, 128, 128),
1989 | new jsc.Color(255, 0, 0),
1990 | new jsc.Color(0, 255, 0),
1991 | new jsc.Color(0, 0, 255),
1992 | new jsc.Color(0, 255, 255),
1993 | new jsc.Color(255, 255, 0),
1994 | new jsc.Color(255, 0, 255),
1995 | new jsc.Color(32, 32, 32),
1996 | new jsc.Color(64, 64, 64),
1997 | new jsc.Color(96, 96, 96),
1998 | new jsc.Color(159, 159, 159),
1999 | new jsc.Color(191, 191, 191),
2000 | new jsc.Color(223, 223, 223),
2001 | new jsc.Color(8, 8, 8),
2002 | new jsc.Color(16, 16, 16),
2003 | new jsc.Color(24, 24, 24),
2004 | new jsc.Color(40, 40, 40),
2005 | new jsc.Color(48, 48, 48),
2006 | new jsc.Color(56, 56, 56),
2007 | new jsc.Color(72, 72, 72),
2008 | new jsc.Color(80, 80, 80),
2009 | new jsc.Color(88, 88, 88),
2010 | new jsc.Color(104, 104, 104),
2011 | new jsc.Color(112, 112, 112),
2012 | new jsc.Color(120, 120, 120),
2013 | new jsc.Color(135, 135, 135),
2014 | new jsc.Color(143, 143, 143),
2015 | new jsc.Color(151, 151, 151),
2016 | new jsc.Color(167, 167, 167),
2017 | new jsc.Color(175, 175, 175),
2018 | new jsc.Color(183, 183, 183),
2019 | new jsc.Color(199, 199, 199),
2020 | new jsc.Color(207, 207, 207),
2021 | new jsc.Color(215, 215, 215),
2022 | new jsc.Color(231, 231, 231),
2023 | new jsc.Color(239, 239, 239),
2024 | new jsc.Color(247, 247, 247),
2025 | new jsc.Color(0, 0, 0),
2026 | new jsc.Color(0, 51, 0),
2027 | new jsc.Color(0, 102, 0),
2028 | new jsc.Color(0, 153, 0),
2029 | new jsc.Color(0, 204, 0),
2030 | new jsc.Color(0, 255, 0),
2031 | new jsc.Color(0, 0, 51),
2032 | new jsc.Color(0, 51, 51),
2033 | new jsc.Color(0, 102, 51),
2034 | new jsc.Color(0, 153, 51),
2035 | new jsc.Color(0, 204, 51),
2036 | new jsc.Color(0, 255, 51),
2037 | new jsc.Color(0, 0, 102),
2038 | new jsc.Color(0, 51, 102),
2039 | new jsc.Color(0, 102, 102),
2040 | new jsc.Color(0, 153, 102),
2041 | new jsc.Color(0, 204, 102),
2042 | new jsc.Color(0, 255, 102),
2043 | new jsc.Color(0, 0, 153),
2044 | new jsc.Color(0, 51, 153),
2045 | new jsc.Color(0, 102, 153),
2046 | new jsc.Color(0, 153, 153),
2047 | new jsc.Color(0, 204, 153),
2048 | new jsc.Color(0, 255, 153),
2049 | new jsc.Color(0, 0, 204),
2050 | new jsc.Color(0, 51, 204),
2051 | new jsc.Color(0, 102, 204),
2052 | new jsc.Color(0, 153, 204),
2053 | new jsc.Color(0, 204, 204),
2054 | new jsc.Color(0, 255, 204),
2055 | new jsc.Color(0, 0, 255),
2056 | new jsc.Color(0, 51, 255),
2057 | new jsc.Color(0, 102, 255),
2058 | new jsc.Color(0, 153, 255),
2059 | new jsc.Color(0, 204, 255),
2060 | new jsc.Color(0, 255, 255),
2061 | new jsc.Color(51, 0, 0),
2062 | new jsc.Color(51, 51, 0),
2063 | new jsc.Color(51, 102, 0),
2064 | new jsc.Color(51, 153, 0),
2065 | new jsc.Color(51, 204, 0),
2066 | new jsc.Color(51, 255, 0),
2067 | new jsc.Color(51, 0, 51),
2068 | new jsc.Color(51, 51, 51),
2069 | new jsc.Color(51, 102, 51),
2070 | new jsc.Color(51, 153, 51)];
2071 |
2072 | //[16777215, 0, 16777215, 8421504, 16711680, 65280, 255, 65535, 16776960, 16711935, 2105376, 4210752, 6316128, 10461087, 12566463, 14671839, 526344, 1052688, 1579032, 2631720, 3158064, 3684408, 4737096, 5263440, 5789784, 6842472, 7368816, 7895160, 8882055, 9408399, 9934743, 10987431, 11513775, 12040119, 13092807, 13619151, 14145495, 15198183, 15724527, 16250871, 0, 13056, 26112, 39168, 52224, 65280, 51, 13107, 26163, 39219, 52275, 65331, 102, 13158, 26214, 39270, 52326, 65382, 153, 13209, 26265, 39321, 52377, 65433, 204, 13260, 26316, 39372, 52428, 65484, 255, 13311, 26367, 39423, 52479, 65535, 3342336, 3355392, 3368448, 3381504, 3394560, 3407616, 3342387, 3355443, 3368499, 3381555]
2073 | }) (jsc);
2074 |
--------------------------------------------------------------------------------